Concatenating two ViewModels - c#

I have two instances of the same ViewModel that I would like to concatenate:
var queryNew = from a in ICDUnitOfWork.AlphaGroups.Find()
join e in ICDUnitOfWork.Alphas.Find()
on a.AlphaGroupID equals e.AlphaGroupID into g
join c in ICDUnitOfWork.Codes.Find()
on a.CodeID equals c.CodeID into co
select new HomeSearchViewModel
{
Alphas = g,
AlphaGroups = a,
AlphaGroupCode = co.FirstOrDefault(),
SearchTerm = searchTerm,
AlphasCodes = null
};
var codequery = from a in ICDUnitOfWork.Alphas.Find()
join c in ICDUnitOfWork.Codes.Find()
on a.CodeID equals c.CodeID into g
select new HomeSearchViewModel
{
AlphasCodes = g
};
var allResults = queryNew.Concat(codequery);
This gives me an error stating:
The type 'ICD.ViewModels.HomeSearchViewModel' appears in two
structurally incompatible initializations within a single LINQ to
Entities query. A type can be initialized in two places in the same
query, but only if the same properties are set in both places and
those properties are set in the same order.
How can I join these results together?

Well the solution was really dumb on my part. I added a navigation property to the table I was trying join and everything is working now.
whoops!

Concat isn't really the right thing to do here, a simple for loop should be enough. From the looks of your query you could possibly use the AlphaGroupCode as your unique identifier for the mapping e.g.
var codequery = ...
select new HomeSearchViewModel
{
AlphaGroupCode = c.FirstOrDefault()
AlphasCodes = g
};
foreach (var q in queryNew)
{
q.AlphaCodes = codequery.Where(x => x.AlphaGroupCode == q.AlphaGroupCode)
.FirstOrDefault()
.AlphaCodes;
}

You could try evaluating the queries before hand, calling something like "ToList()":
var allResults = queryNew.ToList().Concat(codequery.ToList());

If you don't mind doing it as two queries then calling AsEnumerable() will concatenate in local memory with no problems.
var result = queryNew.AsEnumerable().Concat(codequery);
Here the AsEnumerable() will still defer execution of the queries (which is what your code seems to suggest), however if you want immediate execution do as Arthur suggests and call a cacheing function e.g. ToList() or ToArray()

You must fill with null all other properties
var codequery = from a in ICDUnitOfWork.Alphas.Find()
join c in ICDUnitOfWork.Codes.Find()
on a.CodeID equals c.CodeID into g
select new HomeSearchViewModel
{
Alphas = null,
AlphaGroups = null,
AlphaGroupCode = null,
SearchTerm = null,
AlphasCodes = g
};
var allResults = queryNew.Concat(codequery);

Related

How to assign values to a list by linq without for or foreach statements?

I want to compare two lists and assign 1st list to another in case of requirement.
var getdetail=_readonlyservice.getdetail().ToList();
foreach(var item in docdetail)
{
var temp=getdetail.firstordefualt(i=>i.Id=item.Id)
if(temp==null) continue;
item.code=temp.code;
}
I want to implement top statements in linq .any help ?
Think so..
var getdetail=_readonlyservice.getdetail().ToList();
var tempList = from dd in context.docdetail
join g in context.getdetail on dd.Id equals g.Id
select new // Your type
{
// Columns...
Code = g.Code
}
I believe you are trying to do like the way I did, although I was going to join table.
var result = (from e in DSE.employees
join d in DSE.departments on e.department_id equals d.department_id
join ws in DSE.workingshifts on e.shift_id equals ws.shift_id
select new
{
FirstName = e.FirstName,
LastName = e.LastName,
Gender = e.Gender,
Salary = e.Salary,
Department_id = e.department_id,
Department_Name = d.department_name,
Shift_id = ws.shift_id,
Duration = ws.duration,
}).ToList();
// TODO utilize the above result
I was using DTO method to do this. And then you return result(as this case is result).
You may view the whole question and solution here.
As this case, you are not required to put foreach loop, as the query said from every row in yourdatabase.table

Incorporate Enum.GetName(...) into Linq Query

I have the enumeration:
public enum CmdType {
[Display(Name = "abc")]
AbcEnumIdentifier = 0,
[Display(Name = "xyz")]
XyzEnumIdentifier = 1,
...
}
I'd like to get the names of each enumeration into my query, but even using .WithTranslations() I'm getting this error:
LINQ to Entities does not recognize the method 'System.String
GetName(System.Type, System.Object)' method, and this method cannot be
translated into a store expression.
The query:
var joinedRecord =
(
from m in mTable
join b in bTable on m.Id equals b.aRefId
select new {
aId = a.Id,
aAttrib1 = a.Attrib1
...
bCmdType = Enum.GetName(typeof(CmdType), b.CmdType)
}
).WithTranslations();
How do I return a generated value using Enum.GetName(...) within the query?
LINQ to entities tries to translate your query to SQL and it fails to do so, because there is no equivalent of the Enum.GetName method in SQL.
You need to materialize the results of the query and convert the enum values to their name in the memory.
var joinedRecords = (
from m in mTable
join b in bTable on m.Id equals b.aRefId
select new {
aId = a.Id,
aAttrib1 = a.Attrib1
...
bCmdType = b.CmdType
}
).AsEnumerable() //Executes the query, further you have simple CLR objects
.Select(o => new {
aId = o.Id,
aAttrib1 = o.Attrib1
...
bCmdTypeName = Enum.GetName(typeof(CmdType), o.CmdType)
});
You are calling Enum.GetName(typeof(CmdType), b.CmdType) which cannot be translated to SQL as the Enum definition is not in the DB if you take a look at your rows you'll see there is an int instead of the name of the Enum value in question.
Try this:
var joinedRecord =
(
from m in mTable
join b in bTable on m.Id equals b.aRefId
select new {
aId = a.Id,
aAttrib1 = a.Attrib1
...
bCmdType = b.CmdType
}
)
.AsEnumerable() // or ToList()
.Select( // map to another type calling Enum.GetName(typeof(CmdType), b.CmdType) )
.WithTranslations();
What this does is that by calling AsEnumerable() or ToList() you are no longer processing an instance of IQueryable<T> (which is what your original query returns, on the bad side once you do this all returned objects will be on memory). So once you have objects in memory you can use them just as any other C# object which should allow you to use the methods you want.
Try casting to AsEnumerable() so you can use LINQ to Objects. LINQ to Entities will try to translate it to SQL for which there is no equivalent:
var joinedRecord =
(from m in mTable
join b in bTable on m.Id equals b.aRefId)
.AsEnumerable()
.Select(x => new {
aId = a.Id,
aAttrib1 = a.Attrib1
...
bCmdType = Enum.GetName(typeof(CmdType), b.CmdType)
})
.WithTranslations();
See http://www.lavinski.me/ef-linq-as-emumerable/

Linq updating different table after join process

I have combined 3 of my tables by using linq join. After that i want to update this table by using data that i get from webform. How can i do this ? My implementation is below
public void updateShoes(Shoe shoe)
{
var query = from b in db.BrandTbls.AsQueryable()
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
where shoe.ShoeID == s.ShoeID
orderby m.ModelName
select new
{
s.ShoeID,
s.Size,
s.PrimaryColor,
s.SecondaryColor,
s.Quantity,
m.ModelName,
m.Price,
b.BrandName
};
}
Though your approach is a little bit unclear right now (for e.g. we don't know which entities you are trying to update), however you can modify your code like this,
public void updateShoes(Shoe shoe)
{
var query = from b in db.BrandTbls.AsQueryable()
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
where shoe.ShoeID == s.ShoeID
orderby m.ModelName
select new
{
Shoe = shoe, Brand = b, Model = m
};
foreach(var o in query)
{
o.Shoe.ColorName = "Black";
o.Brand.BrandName = "New Branding";
o.Model.ModelName = "Something else";
}
db.SaveChanges();
}
Rather picking selected properties from each Entity, you can pick whole entity. Then you can update each entity in a loop as I have doing above.
I like the all-in-one linq update. Especially if I need to join on an existing object list.
var UpdQuery = (from b in db.BrandTbls
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
where shoe.ShoeID == s.ShoeID
orderby m.ModelName
select new { b, m, s }
// now for the update portion of the query
).Select(result =>
{
result.s.ShoeID = shoe.ID;
result.s.Size = shoe.Size;
result.s.PrimaryColor = shoe.PrimaryColor;
result.s.SecondaryColor = shoe.SecondaryColor;
result.s.Quantity = shoe.Quantity;
result.m.ModelName = shoe.ModelName;
result.m.Price = shoe.Price;
result.b.BrandName = shoe.BrandName;
return result; // this is important
}).ToList(); // tolist actually runs the query to update the objects
db.SaveChanges(); // write changes back to DB
To update an entity you will need to retrieve the entity from the context, modify the values, then call SaveChanges() to do the update.
foreach( var n in query)
{
var shoe = db.Shoes.Find(n.ShoeID);
shoe.Size = webFormData.Size;
}
db.SaveChanges();

LINQ-to-entities generic == workaround

I have a following LINQ-to-entities query
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var q = (from h in ItemHistory
where h.OperationId ==
(from h1 in ItemHistory
where h1.GenericId == h.GenericId
select h1.OperationId).Min()
select h);
return q;
}
ItemHistory is a generic query. It can be obtained in the following way
var history1 = MyEntitiySet1.Select(obj =>
new History<long>{ obj.OperationId, GenericId = obj.LongId });
var history2 = AnotherEntitiySet.Select(obj =>
new History<string>{ obj.OperationId, GenericId = obj.StringId });
In the end of all I want a generic query being able to work with any entity collection convertible to History<T>.
The problem is the code does not compile because of GenericId comparison in the inner query (Operator '==' cannot be applied to operands of type 'T' and 'T').
If I change == to h1.GenericId.Equals(h.GenericId) I get the following NotSupportedException:
Unable to cast the type 'System.Int64' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types.
I've tried to do grouping instead of subquery and join the results.
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var grouped = (from h1 in ItemHistory
group h1 by h1.GenericId into tt
select new
{
GenericId = tt.Key,
OperationId = tt.Min(ttt => ttt.OperationId)
});
var q = (from h in ItemHistory
join g in grouped
on new { h.OperationId, h.GenericId }
equals new { g.OperationId, g.GenericId }
select h);
return q;
}
It compiles because GenericId's are compared with equals keyword and it works but the query with real data is too slow (it has been running for 11 hours on dedicated postgresql server).
There is an option to build a whole expression for the outer where statement. But the code would be too long and unclear.
Are there any simple workarounds for equality comparison with generics in LINQ-to-entities?
Try this, I think it should accomplish what you want without the extra query/join
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var q = from h in ItemHistory
group h by h.GenericId into tt
let first = (from t in tt
orderby t.GenericId
select t).FirstOrDefault()
select first;
return q;
}
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var grouped = (from h1 in ItemHistory
group t by h1.GenericId into tt
select new
{
GenericId = tt.Key,
OperationId = tt.Min(ttt => ttt.OperationId)
});
var q = (from h in ItemHistory
join g in grouped
on new { h.OperationId, h.GenericId }
equals new { g.OperationId, g.GenericId }
select h);
return q;
}
You could also set a generic constraint on T for an IItemHistory inteface that implements the GenericId and OperationId property.
My question already contains a solution. The second method with group + join works well if the table is properly indexed. It takes 3.28 seconds to retrieve 370k rows from the database table. In fact in non-generic variant the first query is slower on postgresql than the second one. 26.68 seconds vs 4.75.

Need help on LINQ query left joins and multiple fields

I have the following SQL query that I would like to rewrite into LINQ:
SELECT gp.Name
, r.DateOfRace
, ISNULL(SUM(rr.Points), 0) AS Points
FROM Races r
INNER JOIN GrandPrix gp
ON r.GrandPrixId = gp.GrandPrixId
LEFT JOIN Predictions p
ON p.RaceId = r.RaceId
AND p.AdditionalUserInformationId = 2
LEFT JOIN RaceResults rr
ON p.DriverId = rr.DriverId
AND p.FinishPosition = rr.FinishPosition
AND p.RaceId = rr.RaceId
WHERE r.Season = 2010
GROUP BY gp.Name
, p.RaceId
, r.DateOfRace
And this is much I got, when it's still working:
from races in Races
join grandprix in GrandPrixes
on races.GrandPrixId equals grandprix.GrandPrixId
from Predictions in Predictions.Where(v => v.RaceId == races.RaceId).DefaultIfEmpty()
select new
{
DateOfRace = races.DateOfRace,
GrandPrix = grandprix.Name,
}
When I go further, things go wrong - I can't for example get the AND p.AdditionalUserInformationId = 2 right.
I hope somebody can help!
You can do the following:
join p in Predictions
on new { p.RaceId, p.AdditionalUserInformationId } =
new { r.RaceId, AdditionalUserInformationId = 2 } into ps
from p in ps.DefaultIfEmpty()
join rr in RaceResults
on new { p.DriverId, p.RaceId, p.FinishPosition } =
new { rr.DriverId, rr.RaceId, rr.FinishPosition } into rrs
from rr in rrs.DefaultIfEmpty()
You use the ability of C# to structurally compare anonymous types. Two anonymous types are created with the same properties, which makes them instances of the same class. These instances can then be compared.
join grandprix in GrandPrixes
on new {races.GrandPrixId, p.AdditionalUserInformationId} equals new {grandprix.GrandPrixId,2}

Categories

Resources