Union from two different entities but same viewmodel class - entity-framework-core

I have 2 different entities: EntityA and EntityB.
All fields are Strings.
I have a common ViewModel class: MyViewModel.
I have 2 queries:
var query1 = from a in EntityA select new MyViewModel { field1=a.somefield1, field2= a.somefield2 };
var query2 = from a in EntityB select new MyViewModel { field1=a.somefield3, field2="String Constant" };
EntityA and EntityB are different but my 2 queries gives us the same result: An IQueryable of MyViewModel.
So i am trying to make an union:
var query3 = query1.Union(query2);
I get this error:
"Unable to translate set operation when matching columns on both sides
have different store types".
This is because EF does not put the same datatype for my string constant and a.somefield2. somefield2 is a varchar(100), but "String Constant" is a string and i don't know how EF translate it.
Thanks
The dotnet version is .Net5 and i am using Microsoft.EntityFramework.Core.SqlServer 5.0.10

Related

Not able to use IN query in LINQ with Entity Framework

I am using EF Framework to retrieve the data from SQL DB.
Sub Request Table looks like below:
In this table "org_assigneddept" is foreign key to another Department Table.
I have list of Departments as Input and I want to retrieve only those rows from DB whose org_assigneddept is matching the list.
Please find my whole code:-
private List<EventRequestDetailsViewModel> GetSummaryAssignedDeptEventRequests(List<EmpRoleDeptViewModel> vmDept)
{
List<EventRequestDetailsViewModel> vmEventRequestDeptSummary = new List<EventRequestDetailsViewModel>();
RequestBLL getRequestBLL = new RequestBLL();
Guid subRequestStatusId = getRequestBLL.GetRequestStatusId("Open");
using (var ctxGetEventRequestSumm = new STREAM_EMPLOYEEDBEntities())
{
vmEventRequestDeptSummary = (from ers in ctxGetEventRequestSumm.SubRequests
where vmDept.Any(dep=>dep.DeptId == ers.org_assigneddept)
select new EventRequestDetailsViewModel
{
SubRequestId = ers.org_subreqid
}).ToList();
}
}
It is giving the following error at the LINQ Query level:-
System.NotSupportedException: 'Unable to create a constant value of
type 'Application.Business.DLL.EmpRoleDeptViewModel'. Only primitive
types or enumeration types are supported in this context.'
Please let me know as how can I achieve the result
You cannot pass the department VMs to SQL, it doesn't know what those are.
// Extract the IDs from the view models.. Now a list of primitive types..
var departmentIds = vmDept.Select(x => x.DeptId).ToList();
then in your select statement...
..
where departmentIds.Contains(id=> id == ers.org_assigneddept)
..

Get Discriminator in Linq Select results

I'm trying to make a SQL Query with LinqToEntities which will be as efficient as possible so I would like to avoid iterating after every record I get in results to get a new corrected collection. I'm trying to create a ready collection to send as a result in API just with this one query.
I'm trying to get a discriminator value though with inherited models.
My models are somewhat like these:
public abstract class DbEntity
{
[NotMapped]
public string DiscriminatorValue
{
get
{
return ObjectContext.GetObjectType(GetType()).Name;
}
}
}
public class Foo : DbEntity {
}
public class Bar: DbEntity {
}
This model will create a table in database which will have a column called Discriminator. To get the discriminator value I used my custom DiscriminatorValue property but it won't work in queries like this:
var events = context.MyTable.Select(t => new {
Discriminator = t.DiscriminatorValue
}).ToList();
This below one will obviously work, but it will be much slower imho:
var events = context.MyTable.ToList().Select(t => new {
Discriminator = t.DiscriminatorValue
}).ToList();
Is it possible to get Discriminator value without having to write my custom SQL query myself (like real sql which I know is possible too).

Entity Framework atypical 1-[0..1] -- model-only Association -- EF LINQ select possibilities

Suppose the following tables
ParentEntities
ParentID
ChildEntities
ChildID
ParentID
These tables do not have a FK defined in the schema.
In EF designer, after generating from DB, I add an association:
- Parent Multiplicity: 1
- Child Multiplicity: 0 or 1
When I build, I get the error: "Error 3027: No mapping specified for the following EntitySet/AssociationSet - ParentChild"
But if I try to configure table mapping for the association like this..
Maps to ChildEntities
Parent
ParentID <-> ParentID (parent entity prop <-> child table column)
Child
ChildID <-> ChildID (child entity prop <-> child table column)
.. I get this: Error 3007: Problem in mapping fragments starting at lines xxx, xxx: Column(s) [ParentID] are being mapped in both fragments to different conceptual side properties.
Why this is an error doesn't make sense. Limitation of the current implementation?
[EDIT 1]
I'm able to make this work by creating a 1-N association. That's not ideal, but it works just the same, just have to add a read-only child property in a partial:
public partial class Parent
{
public Child Child { get { return Childs.Any() ? null : Childs.First(); } }
}
This seems like the best solution for me. I had to add a FK to the database to get EF to generate the association and navigation property, but once it was added I was able to remove the FK, and further updates to the model from the DB did not remove the association or Navigation properties.
[EDIT 2]
As I was investigating how to work around not caring about the association being modeled in EF, I ran into another issue. Instead of the read-only Child property I made it normal ..
public partial class Parent
{
public Child Child { get; set; }
}
.. but now I need a way to materialize that from the query:
var query = from parents in context.Parents
// pointless join given select
join child in context.Childs
on parents.ParentID equals child.ParentID
select parents;
I can select an anonymous type ..
// step 1
var query = from parents in context.Parents
join child in context.Childs
on parents.ParentID equals child.ParentID
select new { Parent = parents, Child = child };
.. but then I've got to consume more cycles getting that into my entity:
// step 2
var results = query.Select(x => {
var parent = x.Parent;
parent.Child = x.Child;
return parent; });
Is there a better/streamlined way to do this from the query select so the EF materializer can do it from the get-go? If not, then I'll resort to Edit 1 methodology ..
Ef Code first requires 1->0..1 relationships for the Child to have the same primary key.
Maybe this a similar restriction In the modeler in this circumstance.
ParentId (Key) required in Both tables.
I have never tried adding such relationships in designer afterwords in DB first.
EDIT: to match your EDIT2:
I would stay on the direction . Use Navigation properties to get from Join back to original class A and B.
query = context.Set<JoinTable>.Where(Jt=>Jt.NavA.Id == ClassAId
&& Jt.navB.Id == ClassBId)
use a select if your need entries returned from either ClassA or ClassB.

Used 'new' operator in LINQ to SQL query, but same instance is referenced in every result

Can anyone explain the behavior I am seeing in the minimal code example below? It seems that for a given field or property, the same two instances of the Entry class are being reused in each iteration of the LINQ to SQL query, even though I use the new operator. The same problem does not show up for LINQ to objects queries. I created a C# console application project using .NET Framework 4 and connecting to a SQL Server 2005 Enterprise database.
public class Set
{
public Entry Field;
public Entry Property { get; set; }
}
public class Entry
{
public int ID;
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database
var resultQuery = (
from x in dc.SomeTable
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets = resultQuery.ToArray();
Test(sets);
var source = Enumerable.Range(0, 10);
var sourceQuery = (
from x in source
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets2 = sourceQuery.ToArray();
Test(sets2);
}
static void Test(Set[] sets)
{
var f = sets[0].Field;
Console.WriteLine(sets.All(x => object.Equals(x.Field, f)));
var p = sets[0].Property;
Console.WriteLine(sets.All(x => object.Equals(x.Property, p)));
Console.Writeline(sets.Length);
Console.WriteLine(object.Equals(f, p));
Console.WriteLine();
}
}
The output of Test() for the LINQ to SQL query is
True
True
1362
False
which indicates that for all of the Set objects produced, all the Field members point to the same single Entry instance and all the Property members point to the same single Entry instance. I.e., the same instance is reused for a respective member in every iteration of the query.
The output of Test() for the LINQ to objects query is
False
False
10
False
which indicates that a new distinct instance is created in each iteration of the query.
Is the LINQ to SQL behavior expected or a bug? Does anyone know if this happens with the Entity Framework?
I don't know if this is a bug or if and why this is expected in LINQ to SQL. I can only answer your last question if that also happens with Entity Framework.
The answer is: No.
With EF you have to use object initializer syntax though when you instantiate the Entry objects. Using the default constructor leads to an exception:
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { Name = "X" },
Property = new Entry { Name = "X" }
}
);
It doesn't matter how you initialize. Using the code above (and with 4 rows in a small test table) I get this output with your test program:
False
False
4
False
False
False
10
False
It looks that there is a big difference between LINQ to SQL and Entity Framework regarding object materialization during projections.
(I've tested with EF 4.1/DbContext.)
Edit
If I take the modified query in my code snippet above also for your LINQ to SQL query and watch the generated SQL I get the following:
SELECT NULL AS [EMPTY]
FROM [dbo].[SomeTable] AS [t0]
Whereas the same with LINQ to Entites creates this query:
SELECT
1 AS [C1],
N'X' AS [C2],
N'X' AS [C3]
FROM [dbo].[SomeTable] AS [Extent1]
My interpretation is that LINQ to SQL parses the projection code and queries only columns for property values which depend on the "row variable" x. All other properties are filled on the client when the objects get materialized. If an object does not depend on a column value at all, LINQ to SQL creates a single constant object and reuses it in the whole result collection.
In constrast to this Entity Framework also sends constant values (independent of x) to the database server. The values get send back to the client and EF treats those values as if they were column values and updates the properties of the objects in the projection.
This leads also to the big difference that something like this...
Random random = new Random();
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { ID = random.Next() },
Property = new Entry { Name = "X" }
}
);
...works in LINQ to SQL because apparently the random function value (which is independent of x) is evaluated on the client and then assigned to the property. But EF wants to translate the right side of the property assignment into SQL and send it as SQL fragment to the database server - which fails and leads to the infamous "...cannot translate into store expression..." exception.
Edit 2
BTW: The last code snippet above still creates only a single Field instance in the whole collection: random.Next() is only evaluated once (and also the constructor of Entry is only called once for the Field object). This now is indeed confusing because writing such code one would expect that you want to have a random value for each row returned from the database. It's not the case.

ADO Entity framework help

Having some experience with Linq to SQL I'm trying out ADO Entity framework now. In Linq to SQL, I would create a Linq to SQL class, drag my tables across to build the data context. Then I'd instantiate the datacontext class and run some lambda against one of the properties in the datacontext class.
Now, with ADO entity framework I add the Entity Data Model class, and add the tables to the data model. My Entity Data Model class now has a bunch of ObjectQuery<> properties, one for each table I added.
Now what do I do with those properties? How do I call them? Anyone have code examples?
Sure. I have a long presentation on this.
As a simple answer to your question, here are some things you can do with the ObjectQuery<T> properties.
Return a list of objects:
IEnumerable<Customer> result = Context.Customers;
return result;
Return one object:
return Context.Customers.Where(c => c.Id == someId).First();
Project onto a presentation model:
return (from c in Customers
where c.Id == someId
select new CustomerPresentation
{
Id = c.Id,
Name = c.Name,
OrderCount = c.Orders.Count(),
PhoneNumbers = from p in c.PhoneNumbers
select new PhoneNumberPresentation
{
AreaCode = p.AreaCode,
// etc.
},
// etc.
}).First();