C# Linq Query With Interface - c#

I have a number of LINQ classes that inherit from the same base class. Each Linq class has its own table, and then the base class is a sort of link to another table. I'll try and illustrate the relationship:
//Base Class
abstract class Element<T>
{
public string Name {get; set;}
public string Species {get; set;}
}
public partial class DogElement : Element<DogElement>
{
public int Legs {get; set;}
public bool hasHair {get; set;}
}
public partial class CatElement : Element<CatElement>
{
public bool hasWiskers {get; set}
}
So DogElement and CatElement are separate physical tables in the database. The Species class will read from the Species table. I basically want to have a generic function in Element that groups the T table with the Species table and returns the result as a T after having set .Species.
//Assume T is DogElement for this example
public IQueryable<T> Collection
{
using (DataBase db = new DataBase())
{
var k = from t in db.GetTable<T>()
where t.SomeID == SomeOtherID
select t;
k = { {Legs = 4, HasHair = True, Species = <null>, Name = <null>}, ...}
I basically want a query that will return an IQueryable<DogElement> with Name
and Species set from a join query. What is the best way to set the Name and
Species values?
return k;
}

Essentially you are asking SQL to handle inheritance (it doesn't do that)... and LINQ doesn't model inheritance either. A good object relational mapper (ORM) will help you piece something together more generically.
That said, here's a quick discussion.
First off, I think it is better to write one LINQ query for each species-animal pair.
You could write a union, switch in the LINQ select, create a new animal, and then cast that animal to a species in one go... then outside the LINQ statement, recast it to T on the way out. This kind of statement sounds messy though.
Although this is less efficient than one big union statement, have you considered this more maintainable option?
var a from speciies select ..
if(T is Dog){
additional linq statement}
else if(T is Cat){
additional linq statement}
that's two trips to the database (slower), but it's more maintainable, and often it is better not to over optimise your code on the first pass.

Related

How to standardize generic Entity Framework C# code using reflection or generics?

I have three database tables which represent comparison scores for common name strings. They're separated into individual tables to speed scanning time. All of them share the same basic structure of four columns: an ID, two strings and score represtning how different the strings are.
The DB is accessed via Entity Framework. In the implementation code, this leads me to having three near-identitical functions, one for each object type:
private bool CheckSurnameJw(string string1, string string2, double threshold)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(string1, string2);
if (jw == null)
{
double dist = JaroWinklerProximity(string1, string2);
JwDistanceSurname newJw = new JwDistanceSurname { Surname1 = string1, Surname2 = string2, JwScore = dist };
_rep.Update(newJw);
_rep.SaveChanges();
return dist >= surnameProximityThreshold;
}
else
{
return jw.JwScore >= threshold;
}
}
Looking at this, while I could nip and tuck slightly, I can't see any clear areas where the function could be sensibly improved by farming code out to another function. But it annoys the hell out of me to have to re-implement the same logic block three times, to deal with three different identity types.
I wrapped all three classes in an interface specifiying the four columns to see if that would help me tidy things up. But it doesn't: I can't use a generic "get" function because each is querying a different table and, likewise, when I create a new instance of the class I need to give it the appropriate type.
Is there a way I can improve this using reflection/generics?
If your four columns all have the same columnNames, I'd definitely go for inheritance using Table Per Type or some kind of Composition
However, if the four columns do not have a common meaning, I'd use an interface.
Table per Type approach
Use this if the four columns represent typically the same thing and you would think that your tables are special kinds of this common thing:
abstract class Common
{
public string String1 {get; set;}
public string string2 {get; set;}
public double Threshold {get; set;}
}
class Table1 : Common
{
public int Id {get; set;}
...
}
class Table2 : Common
{
public int Id {get; set;}
...
}
Your DbContext will be like:
class MyDbContext : DbContext
{
public DbSet<Table1> Table1s {get; set;}
public DbSet<Table2> Table2s {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Table1>().ToTable("Table1s");
modelBuilder.Entity<Table2>().ToTable("Table2s");
}
}
This is enough for entity framework to design two tables, where each table has the four common columns.
A DbSet represents the table in the database. The database doesn't know how CheckSurName. Hence I choose not to let class Common know how to CheckSurName. I create an extension function of Common instead.
See Extension Methods Demystified
static class CommonExtensions
{
public static bool CheckSurName(this Common common)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(common.String1, common.String2);
...
}
}
Usage:
IEnumerable<Table1> myTableCollection = myDbContext.Table1s
.Where(table => table...)
foreach (Table1 table1 in myTableCollection)
{
bool surNameOk = table1.CheckSurName();
Process(surNameOk);
}
Composition Approach
As most developers, I favour composition over inheritance. The approach will be similar, but instead of Inheritance composition is used
class Common ...
class Table1
{
public int Id {get; set;}
public Common Common {get; set;}
}
etc. This will also lead to one Table per type, every table containing all Common properties. The extension function will be similar. The only difference is that you don't perform the check on surnames on your retrieve tables, but on the Common of your retrieved tables:
IEnumerable<Table1> retrievedTables = ...
foreach (Table1 table in retrievedTables)
{
bool SurnameOk = table1.Common.CheckSurName();
...
}
If Common represents something like a person, and your tables represents Items that have a Person, like a SchoolClass with a Teacher, and a School with a HeadMaster, I'd definitely go for this approach. After all a School is not a Person.
Interface approach
You described your columns as if only their types where common, not the names, nor their meaning. You just have two strings and one double, (and an Id, which is lost in your CheckSurName), and the only common thing is that they are two strings and a double. In that case I'd go for an Interface.
Objects that have properties that are needed to CheckSurName will implement ISurNameCheckable:
interface ISurnameCheckable
{
public string String1 {get;}
public string String2 {get;}
public double Threshold {get;}
}
class Table1 : ISurnameCheckable
{
public int Id {get; set;}
public string Street {get; set;}
public string City {get; set}
// implementation of ISurnameCheckable
public string String1 {get{return this.Street;}}
public string String2 {get{return this.City;}}
...
}
The extension function is almost the same:
public static bool CheckSurName(this ISurnameCheckable surnameCheckable)
{
JwDistanceSurname jw = _rep.GetJwDistanceSurname(
surnameCheckable.String1, surnameCheckable.String2);
...
}

Why doesn't AsQueryable<T> imply a filter on the _t discriminator

Assuming a model of
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof (Dog), typeof (Cat))]
class Animal
{
public ObjectId Id {get;set;}
public string Name {get;set;}
}
class Dog : Animal { public int BarkVolume {get;set;} }
class Cat : Animal { public int PurrVolume {get;set;} }
I can do the following:
var collection = new MongoClient().GetServer().GetDatabase("test").GetCollection<Animal("Animals");
collection.Save( new Dog { Name="spot", BarkVolume=7 } );
collection.Save( new Cat { Name="kitty", PurrVolume=2 } );
However if I then try and query just for cats with
var cats = collection.AsQueryable<Cat>();
foreach(var c in cats)
{
Console.WriteLine("{0} purrs at {1}", c.Name, c.PurrVolume);
}
I'll get an exception "Element BarkVolume does not match any field or property of class Cat".
Of course, if I change my query to:
var cats = collection.AsQueryable<Cat>().Where(x=>x is Cat);
Then no problem, however there then is a warning stating that x is Cat is always true.
Is there a particular reason why the driver doesn't inject a test on the discriminator _t
It's a design decision (which after working with for some time, I agree with). To specify the _t filter you can use the OfType extension method which is cleaner than x => x is Cat.
In the MongoDB C# driver there are typed and untyped options for almost everything. The typed options are only for comfort, they don't change the resulting queries. This is a good thing when you really care about the query performance and index utilization.
For example if you query using a property only the specific type has you don't need to add OfType (and the resulting _t filter) and if you do the query engine might use the _t index which you might not want it to do.

C# Table Per Hierarchy Projection Union

I'm using table per hierarchy to project to model classes. When I use of type in Linq to Entities, all of my results are always the last type which was projected. What I mean is if I have these for domain models:
public interface IPerson { string Name {get;set;} }
public abstract class Person : IPerson { public string Name { get;set; } }
public class Employee : Person{ }
public class Manager : Person { }
And I have a Person table with a Name and type column, and use table per hierarchy to yield me specific Entities (which I'll refer to as EmployeeEntity and ManagerEntity).
When I use this code:
IQueryable<IPerson> people = entities.OfType<ManagerEntity>().Select(x => new Manager
{ Name = x.name }).Concat(entities.OfType<EmployeeEntity>().Select(y => new Employee
{ Name = y.name }));
var projectedPeople = people.ToList();
All of the types of objects in projectedPeople are Employee, even the the objects that should be of type Manager. If I remove the Concat call and run them individually, I get the correct type back (Manager or Employee).
What am I doing wrong here? I wrote some test code that removed Linq from the equation by making dummy lists of objects and calling AsQueryable on them, followed by a projection, and that worked as it should.

Return entity type when using table per type inheritance

Lets say I have the following entities
public abstract class Animal
{
public int Id {get;set;}
}
public class Cat : Animal
{
}
public class Dog : Animal
{
}
Is it possible to determine the type of entity without creating an instance.
var id = 1;
var type = context.Animals.GetTypeOfAnimal(id)
public static Type GetTypeOfAnimal(this ObjectSet<Animal> source, int id)
{
// What shall I do here, I dont want to fetch the instance at this point...
var animal = source.First(a => a.Id == id);
return animal.GetType();
}
One solution I thought about using the following method...
public static Type GetTypeOfAnimal(this ObjectSet<Animal> source, int id)
{
var info = source.Where(a => a.Id == id).Select(a => new {IsDog = a is Dog, IsCat = a is Cat}).First();
if(info.IsDog) return typeof(Dog);
if(info.IdCat) return typeof(Cat);
return null;
}
There is no way to get this information without query to database. You are using TPT - it means that database contains Animal, Dog and Cat tables. The inheritance in database is modeled through one-to-one relation between Animal and Dog and between Animal and Cat. The minimum what you have to do is query both Animal and Dog tables for that Id (it can exist only in one of them). The first problem is that you cannot query these tables directly with EF because EF can work only with whole entities (not only with parts mapped to single table) - you must use direct SQL. The second problem is fragility of this solution. If you add new derived entity you must fix this query (same happens for your example).
The reason why TPT queries are slow is that EF must query all inheritance tree = in your case Animal joined with Dog concatenated with Animal joined with Cat. There are some performance improvements in .NET 4.5 for querying TPT inheritance tree but it will not affect your query because it simply has to query whole structure.

EF custom selector expression

I have the following simple scenario. I have a Customer class, which is defined in my edmx. I have an Order class as well, and a Customer can have zero or more Orders through its Orders property.
I defined an OrderCount property in my Customer class like this:
public partial class Customer
{
public int OrderCount { get; set; }
}
I would like to easily write Select queries, which load the value of this OrderCount appropriately. I tried doing this in the Customer class:
public partial class Customer
{
public int OrderCount { get; set; }
public static Expression<Func<Customer, Customer>> DetailSelector = c =>
{
c.OrderCount = c.Orders.Count;
return c;
};
}
And then the Select query:
var customersWithOrderCount = ctx.Customers.Select(Customer.DetailSelector);
However, this way I get an error, that the lambda with a statement body can not be converted to an Expression.
Then I tried to do this:
public partial class Customer
{
public int OrderCount { get; set; }
public static Expression<Func<Customer, Customer>> DetailSelector = c => Customer.LoadDetail(c);
public static Customer LoadDetail(Customer customer)
{
customer.OrderCount = customer.Orders.Count;
return customer;
}
}
But this way when I execute the Select query I get the following exception:
LINQ to Entities does not recognize the method 'Customer LoadDetail(Customer)' method, and this method cannot be translated into a store expression.
What would be the easiest way to do this?
UPDATE: Just for clarification, I am specifically looking for a way to do this with an Expression. So I do not want to load the Orders from the database, I just want to fill the OrderCount property.
Thanks,
This is a bit simplistic, but I think stays with a basic working design on the entities. The best way IMHO is to use .Order.Count. If you are pulling it from there, why not keep it there?
If you want to write select queries, include the value from Customers.Orders directly and the proper SQL will be generated for you. Otherwise I would personally include this value to be set in a CustomerRepository class right after I load the customer. Then you always get your customer from one place and you know its set (implies usage of the Repository Pattern of course)

Categories