Unable to cast left join - c#

I am trying to add a feature to my search page. Basically, if a certain condition is true (based on joining with another table), then apply some CSS class. Here are my (simplified) models:
MyTable
int Key
string Someinfo1
string Someinfo2
string CssClass
SomeTable
int Key
string CssClass
Using LINQ, I wish to join the two tables and assign SearchResult.CssClass = SomeTable.CssClass. In reality, there is some logic used for this assignment.
var test = db.MyTable
.GroupJoin(db.SomeTable,
m => m.Key,
s => s.Key,
(m, s) => new {m, s})
.SelectMany(x => x.h.DefaultIfEmpty(),
(x, y) => new MyTable
{
Key = x.m.Key,
Someinfo1 = x.m.Someinfo1,
Someinfo2 = x.m.Someinfo2,
CssClass = y.CssClass
}
This code breaks, giving the error
The entity or complex type 'MyTable' cannot be constructed in a LINQ to Entities query.
If I simply change the casting (x, y) => new MyTable to create an anonymous type (x, y) => new then things work how I expect them to. Though, I need this to have a typed as MyTable to be compatible with the view that currently exists. Why does it break when trying to cast, when it works fine otherwise? Casting after the fact doesn't work either. Thanks in advance
EDIT: To clarify, MyTable maps to a database table with the exception of CssClass. I have configured EF to ignore that element
modelBuilder.Entity<MyTable>().Ignore(m => m.CssClass);
The desired value for MyTable.CssClass comes from SomeTable.
DefaultIfEmpty() is used to include all entries in MyTable. There exist cases where a Key exists in MyTable, but not SomeTable

Just like the error says, you cannot create a new instance of an entity from within a query.
It appears you're trying to override a property of MyTable with a property from SomeTable. One drawback to that solution is that the new CssClass value will be saved back to MyTable if the entity is saved (which ma be what you want, but it doesn't seem like it based on your usage). If you really need to do this, you're going to have to hydrate the entities (e.g. with ToList()) and then loop to update the value with the value from the related entity.
Your best bet is probably going to be to create a type that is independent of your actual entity class that your views use rather than coupling the views to your entity class. It adds some work to map between the two classes but you can avoid problems like the one you're facing. One challenge I can already see with your data model - how do you know if the CssClass value should be saved back to MyTable or SomeTable?

Related

Sorting by count of matching related data Linq, ThenBy doesnt work

I wrote a query that sorts the result based on the amount of matching elements of a given list. This works when using a single OrderBy.
However, since I want to use Pagination, I need to use a ThenBy to make sure the order is always the same.
The current query somehow moves the subquery inside the OrderBy/ThenBy and can't be translated.
How can I re-write this query so that ThenBy would work?
Thanks.
Code:
products
.Select(product => new ProductDto(product)
{
MatchingContainsCount = (from contain in product.Contains
where allergens.Contains(contain.Allergen.Name)
select contain.Allergen).Count(),
MatchingMayContainCount = (from mayContain in product.MayContain
where allergens.Contains(mayContain.Allergen.Name)
select mayContain.Allergen).Count()
})
.OrderBy(dto => dto.MatchingContainsCount)
.ThenBy(dto => dto.Id); // Without this line it works
The Translation error:
Instead assigning Id property inside the constructor, assign the Id property and other properties within the PropertyDto body, similar to MatchingContainsCount property. EF core doesn't translate complex property assignment within the class constructor or methods to SQL. Only the simple assignments. This should fix the problem.

Get SYSTEM_TIME information from a temporal table on Entity Framework code first method

I created my temporal table following instructions on this link "Cutting Edge - Soft Updates with Temporal Tables"
The procedure generally takes two steps:
create the regular table; this is just the kind of work that Code First usually does
alter the table by adding SysStartTime, SysEndTime columns and turning on the SYSTEM_VERSIONING setting
Everything looks good so far.
However, please note that the entity class doesn't have SysStartTime property and SysEndTime property as they are added later. This gives me trouble as I need to get information of SysStartTime from table.
My question is: How can I get it with Entity Framework?
The link also says:
In EF 6, you can only leverage the SqlQuery method of the DbSet class:
using (var db = new EF6Context())
{
var current = db.Bookings.Single(b => b.Id == 1);
var time = DateTime.Now.AddMinutes(-5);
var old = db.Bookings
.SqlQuery("SELECT * FROM dbo.Bookings
FOR SYSTEM_TIME AS OF {0} WHERE Id = 1", time)
.SingleOrDefault();
}
Note that for EF 6, the column names returned in the query need to match the property names on the class. This is because SqlQuery doesn’t use mappings. If column and property names don’t match, then you’d need to alias the columns in the SELECT list, rather than just SELECT *.
I have no clue how to do this or if it solves my problem. Does anyone have any experience on this?
I can think of one solution is to added an extra column AppliedTime on my table by adding AppliedTime to my entity class. It has (almost, but good enough for me) same value as SysStartTime.
Another solution could be use plain SQL to query the table directly.
Thanks.
I have been worked on this one and found a solution. It is actually quite simple. Just use Database.SqlQuery Method
DateTime time = context.Database.SqlQuery<DateTime>("SELECT SysStartTime
FROM dbo.Calibration
WHERE CalibrationID = 1")
.SingleOrDefault();
See Also: Raw SQL Queries

C# LINQ to Entities - Select specified Data from two tables, populate existing Model Classes

I have a database and am using C# LINQ to Entities using Query Syntax.
Each DB table has it's own Entity Framework generated model class, the DB tables and model classes are named Release and Version (there are others but this is my immediate problem).
I'm trying to load specific data into these model classes based on a query.
Essentially I want every Release column & row, along with its associated Version records populated in the Navigation Property Release.Versions.
However, two crucial points here:
1) I only want certain 'Version' properties to be populated from the Query
(I only need some of the data for use in an Overview page - I can't see the point of dragging back all the data (which could be quite sizeable) if I am not using it).
2) I want the query to populate the already existing Model classes of Release and Version.
(Release.Versions Navigation property being populated with the Version records with cherry picked data from point 1 above)
All this I could do in a long winded way with Stored Procedures - no issue, but thought EF Linq would be quicker. Ha. Ha. Haaaa.
So:
Release.ID <---- Primary Key
Release.Col_1 <---- Other Properties (or columns)
Release.Col_2
Release.Col_3
Release.Versions <---- Navigation Property to collection of Version records for each Release.
Version.ID <---- Primary Key
Version.Release_ID <---- Foreign Key to Release Table
Version.Col_1 <---- Many properties, just want first 4 properties obtained from DB.
Version.Col_2
Version.Col_3
Version.Col_4
Version.Col_5
Version.Col_x...
I just can't get the syntax right.
This is what I have (I've tried many other variants but nothing as simple as I remember it being):
var query = (from r in context.Releases
join v in context.Versions on r.ID equals v.Release_ID
select r).ToList();
returnedRecords= new ObservableCollection<Model.Release>(query);
I seem to remember having to use the select new Release { x,y,z } and then a nested new Version { x, y, z} - but cannot for the life of me remember how to do it, or how to get it to populate the Navigation property Versions within the Release class.
Maybe using Lambda syntax???????
EDIT:
OK, it appears I cannot do what I thought I could do.
So, I'm not going to use Query Syntax as most of the tutorials and documentation I can find are in Method Syntax. Plus I think Include only works with Method syntax, so seems a bit pointless using Query Syntax.
Answer marked as correct is how I loaded the Navigation Properties.
You can simply load 'foreign' records for your table by using Include method.
var x = context.Releases.Include("Versions").ToList();
If you want the query to return the model class Release with a nested Version class, you can do it like this:
var query = (from r in context.Releases
join v in context.Versions on r.ID equals v.Release_ID
select new Release
{
releaseColumn1 = r.releaseColumn1,
releaseColumn12 = r.releaseColumn2,
releaseVersion = new Version
{
versionColumn1 = v.versionColumn1,
versionColumn2 = v.versionColumn2
}
}).ToList();

Filling one to many relationship using using Dapper or via Linq

Entity - AllSalesTerritory contains List<MySalesPerson> representing one to many relationship. I have Sql query to fetch the data where the two entities are mapped using a column TerritoryId. I use a following code to fill the entity using Dapper micro ORM:
List<AllSalesTerritory> allSalesTerrotories = _connection.Query<AllSalesTerritory, MySalesPerson, AllSalesTerritory>
(query, (pd, pp) =>
{
pd.SalesPersons.Add(pp);
return pd;
}, splitOn: "BusinessEntityId")
.ToList();
BusinessEntityId is the beginning column for SalesPerson entity on executing the Sql statement
Challenge that I face is, this kind of code helps in easily filling one to one relation, here I get just one value in each List<MySalesPerson>, instead of aggregating those values in the collection, essentially the same result as that of SQL join query. I can easily resolve the issue using a simple foreach loop and aggregating the values for MySalesPerson. However, I want to figure out:
Can Dapper automatically help me achieve it, tried few extensions, but they did not work as expected
Can a Linq code do it for me, since this is somewhat reverse of a SelectMany on an entity with one to many relationship
You can use a dictionary to keep track of the unique AllSalesTerritory objects. Assuming that the TerritoryId property is an int this would work.
var territories = new Dictionary<int, AllSalesTerritory>()
_connection.Query<AllSalesTerritory, MySalesPerson, AllSalesTerritory>
(query, (pd, pp) =>
{
AllSalesTerritory territory;
if(!territories.TryGetValue(pd.TerritoryId, out territory))
{
territories.Add(pd.TerritoryId, territory = pd);
}
territory.SalesPersons.Add(pp);
return territory;
}, splitOn: "BusinessEntityId");
List<AllSalesTerritory> allSalesTerrotories = territories.Values.ToList();
Basically what happens here is that Dapper will return one AllSalesTerritory and one MySalesPerson for each row in the results of your query. We then use a dictionary to see if the current AllSalesTerritory (pd) has been seen before based on the TerritoryId. If so then the local territory variable is assigned the reference to that object. If not then we assign pd to territory and then add that to the dictionary. Then we just add the current MySalesPerson (pp) to the territory.SalesPersons list.

How do I apply the LINQ to SQL Distinct() operator to a List<T>?

I have a serious(it's getting me crazy) problem with LINQ to SQL. I am developing an ASP.NET MVC3 application using c# and Razor in Visual Studio 2010.
I have two database tables, Product and Categories:
Product(Prod_Id[primary key], other attributes)
Categories((Dept_Id, Prod_Id) [primary keys], other attributes)
Obviously Prod_Id in Categories is a foreign key. Both classes are mapped using the Entity Framework (EF). I do not mention the context of the application for simplicity.
In Categories there are multiple rows containing the Prod_Id. I want to make a projection of all Distinct Prod_Id in Categories. I did it using plain (T)SQL in SQL Server MGMT Studio according to this (really simple) query:
SELECT DISTINCT Prod_Id
FROM Categories
and the result is correct. Now I need to make this query in my application so I used:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
I go to check the result of my query by using:
query.Select(m => m.Prod_Id);
or
foreach(var item in query)
{
item.Prod_Id;
//other instructions
}
and it does not work. First of all the Intellisense when I attempt to write query.Select(m => m. or item.shows just suggestions about methods (such as Equals, etc...) and not properties. I thought that maybe there was something wrong with Intellisense (I guess most of you many times hoped that Intellisense was wrong :-D) but when I launch the application I receive an error at runtime.
Before giving your answer keep in mind that;
I checked many forums, I tried the normal LINQ to SQL (without using lambdas) but it does not work. The fact that it works in (T)SQL means that there is something wrong with the LINQ to SQL instruction (other queries in my application work perfectly).
For application related reasons, I used a List<T> variable instead of _StoreDB.Categories and I thought that was the problem. If you can offer me a solution without using a List<T> is appreciated as well.
This line:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
Your LINQ query most likely returns IEnumerable... of ints (judging by Select(m => m.Prod_Id)). You have list of integers, not list of entity objects. Try to print them and see what you got.
Calling _StoreDB.Categories.Select(m => m.Prod_Id) means that query will contain Prod_Id values only, not the entire entity. It would be roughly equivalent to this SQL, which selects only one column (instead of the entire row):
SELECT Prod_Id FROM Categories;
So when you iterate through query using foreach (var item in query), the type of item is probably int (or whatever your Prod_Id column is), not your entity. That's why Intellisense doesn't show the entity properties that you expect when you type "item."...
If you want all of the columns in Categories to be included in query, you don't even need to use .Select(m => m). You can just do this:
var query = _StoreDB.Categories.Distinct();
Note that if you don't explicitly pass an IEqualityComparer<T> to Distinct(), EqualityComparer<T>.Default will be used (which may or may not behave the way you want it to, depending on the type of T, whether or not it implements System.IEquatable<T>, etc.).
For more info on getting Distinct to work in situations similar to yours, take a look at this question or this question and the related discussions.
As has been explained by the other answers, the error that the OP ran into was because the result of his code was a collection of ints, not a collection of Categories.
What hasn't been answered was his question about how to use the collection of ints in a join or something in order to get at some useful data. I will attempt to do that here.
Now, I'm not really sure why the OP wanted to get a distinct list of Prod_Ids from Categories, rather than just getting the Prod_Ids from Projects. Perhaps he wanted to find out what Products are related to one or more Categories, thus any uncategorized Products would be excluded from the results. I'll assume this is the case and that the desired result is a collection of distinct Products that have associated Categories. I'll first answer the question about what to do with the Prod_Ids first, and then offer some alternatives.
We can take the collection of Prod_Ids exactly as they were created in the question as a query:
var query = _StoreDB.Categories.Select(m => m.Prod_Id).Distinct();
Then we would use join, like so:
var products = query.Join(_StoreDB.Products, id => id, p => p.Prod_Id,
(id,p) => p);
This takes the query, joins it with the Products table, specifies the keys to use, and finally says to return the Product entity from each matching set. Because we know that the Prod_Ids in query are unique (because of Distinct()) and the Prod_Ids in Products are unique (by definition because it is the primary key), we know that the results will be unique without having to call Distinct().
Now, the above will get the desired results, but it's definitely not the cleanest or simplest way to do it. If the Category entities are defined with a relational property that returns the related record from Products (which would likely be called Product), the simplest way to do what we're trying to do would be the following:
var products = _StoreDB.Categories.Select(c => c.Product).Distinct();
This gets the Product from each Category and returns a distinct collection of them.
If the Category entity doesn't have the Product relational property, then we can go back to using the Join function to get our Products.
var products = _StoreDB.Categories.Join(_StoreDB.Products, c => c.Prod_Id,
p => p.Prod_Id, (c,p) => p).Distinct();
Finally, if we aren't just wanting a simple collection of Products, then some more though would have to go into this and perhaps the simplest thing would be to handle that when iterating through the Products. Another example would be for getting a count for the number of Categories each Product belongs to. If that's the case, I would reverse the logic and start with Products, like so:
var productsWithCount = _StoreDB.Products.Select(p => new { Product = p,
NumberOfCategories = _StoreDB.Categories.Count(c => c.Prod_Id == p.Prod_Id)});
This would result in a collection of anonymous typed objects that reference the Product and the NumberOfCategories related to that Product. If we still needed to exclude any uncatorized Products, we could append .Where(r => r.NumberOfCategories > 0) before the semicolon. Of course, if the Product entity is defined with a relational property for the related Categories, you wouldn't need this because you could just take any Product and do the following:
int NumberOfCategories = product.Categories.Count();
Anyway, sorry for rambling on. I hope this proves helpful to anyone else that runs into a similar issue. ;)

Categories