Database.SqlQuery -> Entity Framework Objects - c#

I want to use Database.SqlQuery in Entity framework to run a custom JOIN operation. I don't want to use LINQ to do the JOIN because it is doing a horrible job of generating performant SQL on the backend and I just want to control what it does.
So my question is -- How can I get a set of objects (it's a JOIN from table A to table B, and I want both an object of type A and an object of type B) back out from an INNER JOIN operation on Database.SqlQuery?

As far as I know the SqlQuery method uses property names to map columns to properties.
So you can just declare the class with properties of query and then split it to pair A and B.
Example:
public class AB
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
}
var abs = dbContext.Database.SqlQuery<AB>(#"SELECT A.Id, A.Name, B.Title
FROM A JOIN B ON A.Id = B.Id");
var a_and_bs = from ab in abs
select new
{
A = new A { ab.Id, ab.Name },
B = new B { ab.Title }
};

Related

Querying and mapping complex objects using Linq-to-SQL

I have the following two tables:
ChildTable
ID ManyColumns ParentID
1 XXXX 1
2 YYYY 1
3 ZZZZ 4
ParentTable
ID Name
1 aaaa
2 bbbb
3 cccc
4 dddd
I have the following classes representing the above tables:
public class Child
{
public string ID { get; set; }
public string ManyColumns { get; set; }
public string ParentID { get; set; }
}
public class Parent
{
public string ID { get; set; }
public string Name { get; set; }
}
BUT for data transfer, I have the respective classes:
public class ChildDTO
{
public string ID { get; set; }
public string ManyColumns { get; set; }
public ParentDTO Parent { get; set; } //Here is the only IMPORTANT difference
}
public class ParentDTO
{
public string ID { get; set; }
public string Name { get; set; }
}
How can I use LINQ-to-SQL in way I can resolve Child to ChildDTO with:
Minimum queries
Minimum Mappings
I know I could use this option:
List<ChildDTO> ChildDTOs = (from C in context.Childs
join P in context.Parents on C.ParentId equals P.Id
select new ChildDTO(){
ID = C.ID,
ManyColumns = C.ManyColumns,
Parent = P});
But, I am trying to avoid this multiple mappings I have to do on Select statement.
Also, Child Class is constantly changing in the current Beta Phase. So, if I use the options above, I have to constantly update those mappings.
To make it easier for coding, I am using AutoMapper in this way
AutoMapper.Mapper.CreateMap<Child, ChildDTO>()
.ForMember(dst => dst.Parent, opt => opt.ResolveUsing<Resolver_ParentId_to_Parent>().FromMember(src => src.ParentId))
public class Resolver_ParentId_to_Parent : ValueResolver<string, ChildDTO>
{
protected override ChildDTO ResolveCore(string source)
{
return (from P in context.Parents
Where P.Id = source.ToString()
select item).FirstOrDefault();
}
}
Then, I can simply Map it:
List<Child> Childs = (from C in context.Childs select C);
List<ChildDTO> newChildDTOs = AutoMapper.Mapper.Map<List<ChildDTO>>(Childs);
This is good because:
Fast
Clean
Minimum code effort... EVEN when Child Table has changed, by adding or deleting a column. You are always good to go as long as Class Child and Table Child are up-to-date with same properties/column names. AutoMapper does the trick.
The downside:
I am hammering SQL with multiples "ResolveCore" for each new ChildDTO.
What you guys think? Is there a magic way to resolve Child to ChildDTO in 1 shot only, without manual mappings, without hammering SQL?
Just dreaming:
List<ChildDTO> ChildDTOs = (from C in context.Childs
join P in context.Parents on C.ParentId equals P.Id
select SuperConversor(new ChildDTO())).ToList;
I would go with your approach using the automapper with a modification. Add a Parent member to your Child class. Then you can load it in the query directly (Loading Related Entities) so you will have it in the Child instance without using the automapper resolver and without having multiple queries for a single child.
Also, you could consider other mappers. We switched from using automapper to emitmapper, since we found it was performing ~10 times faster. But that requires some testing, we had complex classes going down several levels.

Can PetaPoco poplulate a list of view models which contain multiple POCOs within each?

I'd like to populate a list of CharacterViewModel with a single query if possible, but I'm unsure how, nor if PetaPoco can even do something like this. This is what the object and query look like:
public class CharacterViewModel
{
public Character Character { get; set; }
public Entity Entity { get; set; }
public Faction Faction { get; set; }
}
var characters = db.Query<CharacterViewModel>(
#"SELECT c.*,e.*,f.*
FROM [Character] c
INNER JOIN [Entity] e ON e.Id = c.EntityId
INNER JOIN [Faction] f ON f.Id = e.FactionId
WHERE c.UserId = #0", 1)
Somehow I'd need to tell PetaPoco to map each JOIN to the respective POCO within the view model. Is this possible or am I going about it the wrong way?
Modify your POCOs as follows:
public class Faction
{
// Other properties
[PetaPoco.ResultColumn]
public Entity Entity { get; set; }
}
public class Entity
{
// Other properties
[PetaPoco.ResultColumn]
public Character Character{ get; set; }
}
public class Character
{
// Properties of character object
}
Modify your query syntax as follows:
var sql = Sql.Builder
.Append("SELECT c.*,e.*,f.*")
.Append("FROM [Character] c")
.Append("INNER JOIN [Entity] e ON e.Id = c.EntityId")
.Append("INNER JOIN [Faction] f ON f.Id = e.FactionId")
.Append("WHERE c.UserId = #0", 1)");
var characters = db.Query<Character, Entity, Faction, Faction>(
(c, e, f) => { f.Entity = e; e.Character = c; return f;}, sql);
This should return an object graph of the Faction object. Note that the fourth parameter (Faction) is the return type of the items in the collection.
This worked great! There was no need for a viewmodel at all with PetaPoco handling the nested relationships, and I could get the list of characters with the foreign objects populated. I used the code generator to create the classes directly from the database tables, and created partials to place the [ResultColumn] properties in. Here's how it ended up looking:
public partial class Character
{
[ResultColumn]
public Entity Entity { get; set; }
}
public partial class Entity
{
[ResultColumn]
public Faction Faction { get; set; }
}
sql = Sql.Builder
.Append("SELECT c.*,e.*,f.*")
.Append("FROM [Character] c")
.Append("INNER JOIN [Entity] e ON e.Id = c.EntityId")
.Append("INNER JOIN [Faction] f ON f.Id = e.FactionId")
.Append("WHERE c.UserId = #0", 1);
var characters = db.Fetch<Character, Entity, Faction, Character>(
(c, e, f) => { c.Entity = e; e.Faction = f; return c; }, sql);
Thanks for steering me in the right direction CallMeKags :)

Using linq to store id in object, but display name in gridview?

If I've got a linq statement like this in my ASP.NET website:
var abcList =
(from c in backEnd.GetCList()
join a in backEnd.GetAList()
on c.AId equals d.AId
join b in backEnd.GetBList()
on c.BId equals e.BId
orderby c.CId descending
select new ABC
{
AId = a.AId,
BId = b.BId,
CId = c.CId,
}).ToList();
For the objects a and b, there is also a.AName and b.BName. I want to save the attribute ID in the object ABC, but I want the a.AName to be displayed instead of a.AId. Is that possible to solve?
So I want the object A to consist of the AId alone, but in a GridView I want to display the AName where c.AId = a.AId. Hope it's not too confusing.
Sure, just add a place for AName in ABC, and show it instead in your GridView.
public class ABC
{
public int AId { get; set; }
public string AName { get; set; }
// other stuff
}
// in your query
select new ABC
{
AId = a.AId,
AName = a.AName,
BId = b.BId,
CId = c.CId,
}
You could make this code a bit cleaner (IMO) if you move the property assignments to a constructor:
select new ABC(a, b, c)

Linq: select from multiple tables into one pre-defined entity

I have two tables A and B. The domain object pulls most of its data from A, and some aggregation from B.
For example:
Table A ( id, name );
Table B ( id_A, quantity );
class A {
public int id { set; get; }
public string name { set; get; }
}
class B {
public int id_A { set; get; }
public int quantity { set; get; }
}
var result =
from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new {
Name = a.name,
Total = g.Sum( b => b.quantity )
};
Instead of creating an anonymous type, I'd like to add a property to domain object A called it TotalQuantity and populate it with g.Sum( b => b.quantity ). I'd also like to turn result into IEnumerable instead of var.
My first bet was
class A {
public int id { set; get; }
public string name { set; get; }
public int TotalQuantity { set; get; }
}
IEnumerable<A> result =
from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new A {
name = a.name,
TotalQuantity = g.Sum( b => b.quantity )
};
This operation is not supported by the runtime:
System.NotSupportedException: Explicit construction of entity type 'Data.A' in query is not allowed.
Note that domain A and B doesn't contain any reference to each other. Their relationship is not used explicitly in the application, therefore, I chose not to model it.
How can I neatly populate a list of A without looping through the data stored in the instances of the anonymous class?
This should do it (note I have not tested it so some tweaking may be in order):
IEnumerable <A> result =
(from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new {
Name = a.name,
Total = g.Sum( b => b.quantity )
}).Select(obj => new A {Name = obj.Name, TotalQuantity = obj.Total});
You'll have perform your projection in memory instead of the database. This way the LINQ to SQL provider won't attempt to convert it to an SQL query.
Here's an example:
IEnumerable<A> result = (from a in A join b in B on a.id equals b.id_A
group b by b.id_A into g
select new
{
Name = a.name,
Total = g.Sum(b => b.quantity)
})
.ToArray()
.Select(item => new A
{
Name = item.Name,
TotalQuantity = item.Total
});
The call to the IQueryable<T>.ToArray() method will force the LINQ to SQL provider to run the query against the database and return the results in an array. The final projection is then performed in memory, circumventing the limitations of the LINQ to SQL provider.
Related resources:
LINQ and Deferred Execution
The performance implications of IEnumerable vs. IQueryable

C# + LINQ + ADO.NET EF , join 2 tables and return everything without specifying all fields manually

I have a simple LINQ query on ADO.NET Entity Framework as follows
var result =
from itemA in TableA
join itemB in TableB on itemA.ID = itemB.ID
select ??????
I am trying to select everything from itemA and itemB without specifying all the TableA and TableB.
anything thoughts???
Is this what you need?
var result = from itemA in TableA
join itemB in TableB on itemA.ID equals itemB.ID
select new { itemA, itemB };
Alternately, you could declare a result class that helps you build the result object without specifying all the fields:
class ItemAB
{
public ItemAB(ItemA a, ItemB b)
{
FieldA1 = a.FieldA1;
FieldA2 = a.FieldA2;
FieldB1 = b.FieldB1;
FieldB2 = b.FieldB2;
}
public int FieldA1 { get; private set; }
public int FieldA2 { get; private set; }
public int FieldB1 { get; private set; }
public int FieldB2 { get; private set; }
}
var result = from itemA in TableA
join itemB in TableB on itemA.ID equals itemB.ID
select new ItemAB(itemA, itemB);
From your link query it looks like you have 2 tables with a one to one relationship.
If so, the way to do it is to configure your entity model such that two tables are merged into one entity. For details see:
http://blogs.msdn.com/simonince/archive/2009/03/23/mapping-two-tables-to-one-entity-in-the-entity-framework.aspx

Categories

Resources