Entity Framework can't see computed columns of the View - entity-framework

Does EF support computed columns in SQLite views?
I just added a view to my SQLite database. While EF can see the view and does create an entity for it when I issue "Update Model from Database..." command, the generated entity does not have any property corresponding to the computed column of my view (which btw was the whole reason for which I created the view).
Is the known/documented problem, or am I doing something wrong?
This is my View:
SELECT [Id],
[ProjectId],
[Start],
[End],
[Deleted],
[LastUpdate],
(JULIANDAY ([End]) - JULIANDAY ([Start])) * 86400000 AS [Duration]
FROM [Timeslot]
It cannot see the Duration column for some reason.
Edit
Thinking about CL's answer, I tried to explicitly cast the problematic column to INTEGER, to help SQLite recognize its type:
CAST (((JULIANDAY ([End]) - JULIANDAY ([Start])) * 86400000) AS [INTEGER]) AS [Duration]
Doesn't prove any good.

This is a problem with EF that can be worked around by specifying a default data type for such columns in the connection string, or as an environment variable in System.Data.SQLite.dll.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="DefaultFlags_SQLiteConnection" value="DetectTextAffinity, DetectStringType" />
</appSettings>
</configuration>

Related

Entity Framework - entity using a view giving duplicate data

I have the following view (SQL Server 2012 if it matters):
SELECT
EntityId
,EntityType
,StateId
FROM
SomeTable
INNER JOIN SomeOtherTable
When I generate an entity for this view (EF 6 - database first) it looks like this in the EDMX file:
<EntityType Name="VW_MyView">
<Key>
<PropertyRef Name="EntityId" />
<PropertyRef Name="EntityType" />
</Key>
<Property Name="EntityId" Type="Int32" Nullable="false" />
<Property Name="EntityType" Type="String" Nullable="false" MaxLength="2" FixedLength="false" Unicode="false" />
<Property Name="StateId" Type="Int32" />
</EntityType>
As you can see, the model generator created an entity key on the first two columns. The problem is, the first two columns do not guarantee uniqueness.
So for example I could have data like this in the view:
EntityId EntityType StateId
-------- ---------- -------
1234 CR 1
1234 CR 2
1234 CR 3
When I query the data using linq such as:
using (ContextA context = new ContextA())
{
var zList = context.VW_MyView.Where(f => f.EntityId == 1234
&& f.EntityType == "CR").ToList();
}
I get a list of three items, but like this (notice stateid duplicated):
EntityId EntityType StateId
-------- ---------- -------
1234 CR 1 <-- dupe
1234 CR 1 <-- dupe
1234 CR 1 <-- dupe
I migrated this exact same code from EF 4 (object context templates) to EF 6 (dbcontext templates), and before the migration it did not perform like this.
I know I can manually add an EntityKey to the StateId column, and it will work properly, but I have over 100 views in my model and I don't want to go through each one to check.
Why has this behavior changed, and is there a setting I can enable (globally) to correct this?
EDIT:
So based on the answers, I have been able to gather three ways to prevent this issue.
Add all primary key values from each consisting table into the view
Use nullif() tricks in the view to force columns to be non-nullable, and those be added by EF to the key
Manually add the Entity Key in the model myself
But this doesn't explain really why this happens, and how it could possibly be desired behavior? The EF linq query is simply returning entirely incorrect data, without any exceptions or warnings. I can't imagine this is correct.
I have the same "issue" in EF4 (with an .edmx file using the ObjectContext database-first approach) - not sure why it worked for you.
For Entity Framework, if it doesn't have a specified primary key (like on a table), it will fall back to using all non-nullable columns of that object (here: your view) as its compound PK.
These non-nullable columns are now the key for the table/view, and thus, only one value of that key can exist.
In order to resolve this, you need to either include more columns in your view to make the auto-detected key really unique (by including e.g. the primary key of all underlying base tables), or you need to manually set the key properly to something that works for you.
Another solution I found is by setting entity's MergeOption to NoTracking.
using (ContextA context = new ContextA())
{
context.VW_MyView.MergeOption = System.Data.Objects.MergeOption.NoTracking;
//Rest code goes here...
}
Solution found in this thread

Why can't I use a View containing a Union in Entity Framework 4.0?

I have a View which looks similar to this:
SELECT Id, Name
FROM Users
UNION ALL
SELECT NULL as [Id], NULL as [Name]
When I try to map to this view in Entity Framework, it just fails. I don't get an error, but the view does not exist in my data store. Why is this? Is there a way around it?
I know this is an older question already marked as answered, but I wanted to post an alternative to editing the edmx. I learned this one the hard way, after tons of Google searches and pulling my hair out for hours, trying different options...
For a view, EF attempts to to infer a primary key by identifying columns that are non-nullable
and non-binary (see Create an Entity Key When No Key Is Inferred).
With a view used to flatten related data for lookup purposes, this can result in many columns (or the wrong ones) being inferred as keys.
For a view with a UNION, it can cause the opposite problem, because there may be no true identity column that can be safely included as a key.
To force EF to identify columns as a key, you can use ISNULL() to ensure the value is non-nullable: ISNULL(column_name, replacement_value)
To force EF to not mark a column as a key, you can use NULLIF() to make it nullable: NULLIF(column_name, value_not_equal_to_parameter_1)
If you need to ensure a value is returned, but don't want to have it marked as a key, I believe COALESCE(column_name, replacement_value) will do the job of ISNULL without EF marking the column as a key
If there is truly no viable column available as a primary key (as in a UNION view), you can fake a non-nullable PK through the use of ISNULL() combined with ROW_NUMBER() in your SELECT statement: SELECT ISNULL(ROW_NUMBER() OVER (ORDER BY sort_criteria), 0) as 'ALIASNAME'
As an alternative, the edmx can absolutely be edited directly as Marcos Prieto suggested, but you run the risk of having those changes overwritten the next time you run "Update Model from Database".
Hope this helps anyone who encounters this in the future!
It is because Visual Studio cannot infers the Primary Key of your View.
You can see the error message within edmx file by open it with XML editor and see the SSDL section.
Here is error message that results from my Model(which I created some View like yours within my Database just to emulate) :
Errors Found During Generation:
warning 6013: The table/view 'PhoneBook.dbo.ContactCustomer' does not have
a primary key defined and no valid primary key could be inferred.
This table/view has been excluded. To use the entity,
you will need to review your schema,
add the correct keys, and uncomment it.
It is not true that Union is not supported in EF 4.
But I think the problem is that Visual Studio saw your view as the odd View.
You can doing some experiment by create another View and compares them (using update model from database menu within model designer).
And you can modify the Model by hand (manual typing the edmx file) to define the Primary Key to resolve this.
I had a view that worked perfectly. I modified it (changed the view on a union of 2 tables), updated the model from database and this problem appeared.
I fixed it in 3 steps:
Open the .edmx file with a XML editor.
Uncomment the view's EntityType XML (edmx:StorageModels > Schema) code and add the Key:
<EntityType Name="your_view">
<Key>
<PropertyRef Name="your_id" />
</Key>
<Property Name="your_id" Type="int" Nullable="false" />
<Property Name="other_field" Type="varchar" MaxLength="45" />
</EntityType>
Be sure that EF didn't erased the view in edmx:StorageModels > Schema > EntityContainer (if you have code repository, copy the code from there):
<EntitySet Name="your_view" EntityType="Your_Model.Store.your_view" store:Type="Views" store:Schema="your_schema" store:Name="your_view">
<DefiningQuery>SELECT
`your_view`.`your_id`,
`your_view`.`other_field`,
FROM `your_view` AS `your_view`
</DefiningQuery>
</EntitySet>
I know this is an old question but i faced this issue recently & after trying to do the above mentioned methods i simply created another view that selects from the Union view & i was able to map the new view by updating my entity model.

WCF Rest/Entity Framework - View Not Deserializing as expected

I have a view that returns data like the following:
1 | Abita | NULL | http://www.abita.com/
2 | Abita | Abbey Ale | http://abita.com/brews/abbey_ale.php
I am using WCF REST to get the xml representation of this view, via an entity framework object. When viewing the returned data as xml in a browser, the first row shows data as I expect:
<vw_Url z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
- <EntityKey z:Id="i2" xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" xmlns:a="http://schemas.datacontract.org/2004/07/System.Data">
<a:EntityContainerName>FierceBeersEntities</a:EntityContainerName>
- <a:EntityKeyValues>
- <a:EntityKeyMember>
<a:Key>Brewery</a:Key>
<a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">Abita</a:Value>
</a:EntityKeyMember>
</a:EntityKeyValues>
<a:EntitySetName>vw_Url</a:EntitySetName>
</EntityKey>
<Beer i:nil="true" />
<Brewery>Abita</Brewery>
<RowId>1</RowId>
<Url>http://www.abita.com/</Url>
</vw_Url>
However, the second row doesn't appear to deserialize the row/object correctly, as it doesn't contain the data from row two.
<vw_Url z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
Any idea why this might be?
UPDATE:
I've tracked this down to being caused by a UNION within the view. The rows are unioned together from two different tables, and for some reason, EF is treating the second as a reference to the first. Perhaps this is an EF bug? Any ideas for a workaround?
Sounds like this may be an EF bug/limitation in EF 1.0. http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/9293cf4d-deef-40b1-ab56-a0ee1e770dd9 However, I am using EF 4.0 and it still seems to be an issue. Sigh...
UPDATE: I've tracked this down to being caused by a UNION within the view. The rows are unioned together from two different tables, and for some reason, EF is treating the second as a reference to the first. Perhaps this is an EF bug?
Sounds like this may be an EF bug/limitation in EF 1.0. http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/9293cf4d-deef-40b1-ab56-a0ee1e770dd9 However, I am using EF 4.0 and it still seems to be an issue. Sigh...

Error 3023 using Entity Framework

Using the Entity Framework, I've modeled a fairly simple database schema with an ever-so-slightly more complex class hierarchy. In two places, I'm using single table inheritance with a single NVARCHAR(20) NOT NULL discriminator column. In one of those two places, it works great, no issues. But in the other place, with an almost identical pattern, I get the following error:
Error 3023: Problem in Mapping Fragments starting at lines 371, 375, 379, 382: Column MediaStream.MediaStreamTypeID has no default value and is not nullable. A column value is required to store entity data.
An Entity with Key (PK) will not round-trip when:
((PK does NOT play Role 'MediaStream' in AssociationSet 'FK_MediaStream_SessionID' OR PK is NOT in 'MediaStream' EntitySet OR Entity is type [SlideLinc.Model].MediaStream) AND (PK plays Role 'MediaStream' in AssociationSet 'FK_MediaStream_SessionID' OR PK is NOT in 'MediaStream' EntitySet OR Entity is type [SlideLinc.Model].MediaStream) AND (PK plays Role 'MediaStream' in AssociationSet 'FK_MediaStream_SessionID' OR PK is in 'MediaStream' EntitySet))
Here's the table definition (not including various indexes, foreign keys, etc.):
CREATE TABLE [dbo].MediaStream(
[MediaStreamID] UNIQUEIDENTIFIER NOT NULL,
[SessionID] UNIQUEIDENTIFIER NOT NULL,
[RtmpUri] nvarchar(250) NOT NULL,
[MediaStreamTypeID] nvarchar(20) NOT NULL,
CONSTRAINT PK_MediaStream PRIMARY KEY CLUSTERED
(
[MediaStreamID] ASC
)
I'm using the MediaStreamtypeID column as the discriminator: if it's set to "video", a VideoMediaStream class should be created, and if it's set to "audio", an AudioMediaStream class should be created.
The relevant portions of the EDMX file look like this:
<EntitySetMapping Name="MediaStream">
<EntityTypeMapping TypeName="IsTypeOf(SlideLinc.Model.MediaStream)">
<MappingFragment StoreEntitySet="MediaStream">
<ScalarProperty Name="RtmpUri" ColumnName="RtmpUri" />
<ScalarProperty Name="MediaStreamID" ColumnName="MediaStreamID" /></MappingFragment></EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(SlideLinc.Model.VideoMediaStream)">
<MappingFragment StoreEntitySet="MediaStream" >
<ScalarProperty Name="MediaStreamID" ColumnName="MediaStreamID" />
<Condition ColumnName="MediaStreamTypeID" Value="video" /></MappingFragment></EntityTypeMapping>
<EntityTypeMapping TypeName="IsTypeOf(SlideLinc.Model.AudioMediaStream)">
<MappingFragment StoreEntitySet="MediaStream" >
<ScalarProperty Name="MediaStreamID" ColumnName="MediaStreamID" />
<Condition ColumnName="MediaStreamTypeID" Value="audio" /></MappingFragment></EntityTypeMapping></EntitySetMapping>
<AssociationSetMapping Name="FK_MediaStream_SessionID" TypeName="SlideLinc.Model.FK_MediaStream_SessionID" StoreEntitySet="MediaStream">
<EndProperty Name="MediaStream">
<ScalarProperty Name="MediaStreamID" ColumnName="MediaStreamID" /></EndProperty>
<EndProperty Name="Session">
<ScalarProperty Name="SessionID" ColumnName="SessionID" /></EndProperty></AssociationSetMapping>
So there are multiple things about this error that I don't get:
(1) Why does exactly this same approach work for my other class hierarchy, but not this one? I thought it might be the Entity Designer getting confused, so I deleted this portion of my hierarchy (in the XML), and recreated it, but I'm still getting it. I could try recreating the whole damn thing, but hell, that's a lot of work, and if I'm gonna have to be doing this very often, that doesn't leave a great taste in my mouth about the entity framework.
(2) What is it complaining about in the first place? I don't get how MediaStreamTypeID (which isn't a member of the primary key) has anything to do with the primary key at all, or why the fact that it can't be null is a problem (especially given that this same setup works elsewhere in my model!).
Any thoughts or suggestions?
I had a similar problem, and was able to solve it by setting the "Abstract" property for the base class to "True" and by removing the discriminator column from the base class in the model (either in the *.edmx file or in the designer view within Visual Studio).
I got the exactly same error but maybe with different reason from yours.
In the code below, I mis-copied some codes so 2 of inherited classes (LeveledItem and Team) are of the same "Type".
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new ScrumDbContextInitializer());
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<LeveledItem>()
.Map<LeveledItem>(m => m.Requires("Type").HasValue(typeof(LeveledItem).Name))
.Map<Team>(m => m.Requires("Type").HasValue(typeof(LeveledItem).Name))
.Map<Story>(m => m.Requires("Type").HasValue(typeof(Story).Name))
.Map<Task>(m => m.Requires("Type").HasValue(typeof(Task).Name)) .Map<Sprint>(m => m.Requires("Type").HasValue(typeof(Sprint).Name));
After the second one was changed to "typof(Team).Name", the error was fixed.
I had a similar problem to this, just out of interest, does deleting the .EDMX file and recreating it from scratch solve your problem?
What caused the problem:
Created a set of tables with some 0..* mappings
Generated the Entity Framework class, customised a whole bunch of Navigation properties
Went back to the DB and changed the cardinality of some of the 0..* to 1..* relationships - ie: set some of the FKs to !nullable
Updated the Entity Framework
Recompiled and BOOM I got a compilation error similar to yours
There seems to be an issue where the "Update Model from Database" command doesn't update the changed relationships correctly.
The solution was to open the EDMX file, look for the <Association Name="FK_XXX_XXX"> elements that were generated the first time and change the Multiplicity attribute on the relevant End point from Multiplicity="0..1" to Multiplicity="1"
I encountered this error when I inadvertently mapped 2 classes to the same table via the [Table] attribute (same effect via modelBuilder ToTable())

How to get store type of an entity set

I'm trying to filter entities based on their store types (either table or view).
I have 2 entities in my test project, one's source is a table and the other's source is a view.
<EntitySet Name="Test" EntityType="TestModel.Store.Test" store:Type="Tables" Schema="dbo" />
<EntitySet Name="TestView" EntityType="TestModel.Store.TestView" store:Type="Views" store:Schema="dbo" store:Name="TestView">
The code sample above is taken from model's edmx file's SSDL section.
I think the store:Type information in SSDL is what i need but i couldn't find a way to retrieve that value using entity-framework api.
Any help will be appreciated.
Well you can query the metadata in the SSDL by looking in the SSpace or the StoreItemCollection.
i.e.
var sspaceEntitySets = context.MetadataWorkspace
.GetItems<EntityContainer>(DataSpace.SSpace)
.First().BaseEntitySets.OfType<EntitySet>();
var entitySet = sspaceEntitySets.First();
var tableType = entitySet
.MetadataProperties["http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator:Type"]
.Value.ToString();
Unfortunately this isn't going to help you tie your classes to whether they come from a table or a view. Because the Entities (i.e. the ones you code against in CSpace) rather than the ones that describe the shapes of the table (i.e. SSpace ones) are in CSpace and in order to know whether an Entity comes from a view or table, you would need to be able to get from the CSpace EntitySet to SSpace EntitySet via the Mapping.
Unfortunately the EF doesn't expose public CSSPace (i.e. there is no way to use the API to read the MSL fragment of the EDMX).
So in order to do this you would have to manually reason over the MSL element, probably using LINQ to XML or something.
Hope this helps
Alex