When I use against a dbase(oracle) View
from f in MYVIEW
where f.Order=="HERE"
select f
I get identical results(rows).
With...
from f in MYVIEW
where f.Order=="HERE"
select f.ColA
I get the correct results returned for the ColA
I know this must be a newbie question. Still learning...thanks in advance
The reason is that EF by default needs to identify uniquely every record. Because of that every entity must have unique key. Views don't have a key so EF infers the key by using all non-nullable columns which don't contain binary data. Now EF expects that these columns will make the entity uniquely identifiable. If they don't you will end with the problem you see in your first example. When EF reads entities from result set it check the key and if the entity with the same key was already created it uses that instance instead of creating a new one -> all records from the result set with the same values in key columns will be represented by the same entity instance. I described today how to avoid this problem with views.
Your second example uses projection. In such case no entity instances are constructed and EF simply returns values.
Related
I have three database views that are mapped in Hibernate as entities.
The entities are in a parent-child relationship (1 parent (A), 2 children(B & C)).
One of the children views (B) uses Oracle's dbms_utility.get_hash_value() to calculate its ID.
This is because it does a UNION over several tables that use different ID sequences and thus the IDs from there may not be unique.
I now have the very puzzling effect that a simple entityManager.find(B.class, id) cannot find the appropriate row.
When I look at the children through a loaded parent (A) entity, I can see that the ID shown in B is completely different from the one in the database. If I use this ID with entityManager.find(B.class, hibernateId), Hibernate finds the appropriate entity.
The database, on the other hand, only returns a value when using the ID shown in the ID column there (and not with the ID Hibernate shows).
Child entity C does not use the hash function and does not show this peculiar behaviour - which means the hash must be responsible.
Does anyone have an idea why?
We found the reason:
Child view B used all of its (content containing) columns as a string concatenation for the hash function.
This included date fields, which were not explicitly formatted when creating the string.
So, when Hibernate selected from the view, it obviously used another format than SQL Developer and thus produced completely different (but consistent) IDs.
Explicitly formatting the used date fields removed the problem.
In a data model like this (http://alanstorm.com/2009/img/magento-book/eav.png) I want to get the value from an EAV_Attribute using Linq to SQL.
Assuming that an EAV_Attribute only exists in one inherited table (varchar, decimal, int, etc.) how can I get it in a linq query?
I know that I can use the Inheritance for this, but I want to execute it in the SQL Database side...
Is it possible to do a kind of Coalesce in Linq, considering that the elements have different types?
EAV and linq is not a happy marriage. I think your best shot is to create an unmapped property in eav_attribute that resolves the value (as object) from it's typed attribute child. With entity framework, you won't be able to use this property in an expression (i.e. not in a Where or Select), You must convert to IEnumerable first to access it. (Linq-to-sql may allow it because it can switch to linq-to-objects below the hood).
Another option is to create a calculated column of type sql_variant that does the same, but now in t-sql code. But... EF does not suport sql_variant. You've got to use some trickery to read it.
That's the reading part.
For setting/modifying/deleting values I don't see any shortcuts. You just have to handle the objects as any object graph with parents and children. In sql server you can't use cascaded delete because it can only be defined for one foreign key. (This may tackle that, but I never tried).
So, not really good news, I'm afraid. Maybe good to know that in one project I also work with a database that has an inevitable EAV part. We do it with EF too, but it's not without friction.
First of all, I recommend using TPH and not TPT for EAV tables. (One table with multiple nullable value columns (one per type) + discriminator vs. one table per type.)
Either way, if you modelled the value entity as an abstract class (containing the two IDs) with an inheriting entity per value data type that adds the value property, then your LINQ should look like this:
var valueEntity = context.ProductAttributes.Where(pa =>
pa.ProductId == selectedProductId
&& pa.AttributeTypeId == selectedAttributeTypeId)
.SingleOrDefault() as ProductAttributeOfDouble;
if valueEntity != null
return valueEntity.Value;
return null;
Where the entity types are: Product, AttributeType, ProductAttribute, ProductAttributeOfDouble, ... ProductAttributeOfString.
There have been numerous questions posed on this site relating to the retrieval of the IDENTITY after an insert is performed. The way we have been getting the identity is to make the call below, immediately after calling SaveChanges();
context.MyClass.OrderByDescending(c => c.Id).FirstOrDefault();
This seems to work consistently may be completely adequate; however, it has the appearence of opening up a potential for error, should another record be added in between the calls. So the first question is, given that EF performs withing a transacional context, is this method sound?
Secondly, the answer provided to the following question suggests there may be a better way.
Linq to SQL - How to find the the value of the IDENTITY column after InsertOnSubmit()
In that answer, after calling SubmitChanges(), the following call (where "tst" represents the user's class) retrieves the value.
Response.Write("id:" + tst.id.ToString)
This appears to work exactly the same way in LINQ to Entities, where after the call to save changes the instance of the class now includes the id.
context.MyClass.Add(myClass);
context.SaveChanges();
int myNewIdentity = myClass.Id;
Since we are asking for the the actual ID of the class instance (actual record) it would appear to be failsafe. And, it seems logical that the designers of EF should make such basic functionality available. Can anyone confirm that this is proper way to get the identity or at least a best practice?
Yes, LINQ-to-Entities (and LINQ-to-SQL for that matter) will set the generated identity column back in the entity for you after SaveChanges is called. It will also do so for any foreign keys that couldn't be set ahead of time (for instance, a new parent row + a new child row are saved together, and after SaveChanges you'll have the right value in the child row's FK value).
Your particular concern is documented in the 'Working with Entity Keys' page:
http://msdn.microsoft.com/en-us/library/dd283139.aspx
The particular section is 'Entity Keys and Added Objects' and the particular steps are:
4 - If the INSERT operation succeeds, server-generated values are written back to the ObjectStateEntry.
5 - The ObjectStateEntry updates the object with the server-generated value.
Entity framework returning only one value but the list size is correct
I have a table that does not have primary id and I need to get or select all the values in it.
What I see is when I do the selection with linq the number of objects is correct but it is the first row over and over.
I am simply doing something like this
List<MyValueType> valuesInDB = myDb.MyValueTypes.ToList();
Problem is I may get thousands of rows (which is correct) but the rows all have the same exact data.
I am using VS 2010 and used the wizard to create my EF object.
The problem is that entity framework is not able to work with entity without a key. So if your table doesn't specify a key, entity framework will infer its own. The key created by EF is composed of all non-nullable non-binary columns.
So if you for example have single non-nullable column in your entity which have only very small set of values (like enum) you will be able to load only single entity "per value". The reason is an inner implementation of the context and the state manager which uses Identity map pattern. When data record is retrieved from database, EF will first check an entity key and tries to find an object with the same key in its internal storage. If an object is found it will use that object instead of data record retrieved (despite of different data). If an object with the key is not found a new object is materialized and added to internal storage.
That is the purpose of Identity map - object with given key should be created only once by each context. Identity map is core pattern in ORM.
I wrote about Identity map also in this question.
I would suggest searching for the word "Warning" in your EDM's designer.cs file. It might tell you if Entity Framework is having any issues with your table.
I really can't comment much in the absence of the table design. I tried replicating your problem but wasn't able to do so. Here is what I did:
Created a table with no primary key but it had a unique key on an ID column. Entity Framework was able to infer a primary key and when I fetched the data, I not only got the correct number of rows but also the corrects data in those rows.
Created a table with no primary key and no unique key. Also there was no column called ID. Entity Framework excluded this table in the EDM that was generated. Consequently I wasn't able to query this table at all.This was displayed as a warning in the EDM designer file.
It would be better if you can share the create script for your table.
I have a Tags table whose schema consists of only ID and Name (unique). Now, from the GUI user can enter tags for a BlogPost. When the data is saved, with tags stored in an array of string (names), I want to add tags whose names don't yet exist to the Tag table and ignore tags whose names already exist AND get back the list of all tag entities (including the existing and newly added ones). How can I do this in Entity Framework in just 1 SQL roundtrip?
For the returned tags, I want to associate them to the to-be-added BlogPost object (which is just instantiated and not stored in DB via EF yet). Is it still possible that this step can be combined with #1 in 1 single roundtrip or must I have to issue another query?
I don't believe the Entity Framework does batch inserts at all (at present). So if you must keep the number of DB roundtrips so low, you're probably going to have to use a stored procedure or a database trigger. Fortunately, the Entity Framework supports stored procedures which return entity types. There is documentation on MSDN about this. You could create a proc which accepts a string list of tags and returns tag entity instances. Alternately, you could add a VARCHAR column to your post table for a delimited list of tags, and parse it in the trigger.