Cannot insert explicit value for identity column - vb.net

I'm getting the above error when creating a new record. I don't want to insert the identity -- the database has it auto generated and that is great.
Here is the exact exception:
[System.Data.UpdateException]
{"An error occurred while updating the entries. See the inner exception for details."}
{"Cannot insert explicit value for identity column in table 'PartRevisions' when IDENTITY_INSERT is set to OFF."}
Here are the mappings:
Public Class PartContext
Inherits DbContext
Public Property Parts As DbSet(Of Part)
Public Property PartRevisions As DbSet(Of PartRevision)
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
modelBuilder.Entity(Of PartRevision)().HasKey(Function(r) r.Id).Property(Function(r) r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
End Sub
End Class
<Table("Parts")>
Public Class Part
<Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)>
Public Property Id As Integer
Public Property PartNumber As String
Public Property Owner As String
End Class
<Table("PartRevisions")>
Public Class PartRevision
Inherits Part
Public Property OriginalId As Integer
Public Property RevisionDate As DateTime
Public Property RevisionNumber As Integer
Public Property RevisionBy As String
End Class
If I don't use inheritance it works fine. If I make Id overridable and also specify the attributes on the sub class it still doesn't work.
I'm doing the OnModelCreating stuff just because I'm trying to get it to work. I feel like it should work without this. Of course it doesn't even work with this...
The following query works fine when I execute it in SQL Management Studio:
insert into PartRevisions (originalid, revisiondate, revisionnumber, revisionby, partnumber, owner)
values (1, '1/1/2013', 1, 'eep', '123', 'ME')
Here is a gist with the full program. I was trying this out in a test project because I assumed I'd run into some issues doing inheritance in EF (never done yet).
https://gist.github.com/eyston/4956444
Thanks!

The PartRevisions table must not have the Id column set as an autogenerated identity, only the table Parts for the base type. The two tables have shared primary keys. EF joins the two tables when it queries a PartRevision and it inserts rows into both tables if a PartRevision entity is inserted. Because both rows must have the same Id only one can be an identity.

Either remove the auto identity property from the "Id" column. Or alternatively you can use in your Query/Stored procedure. This will enable to to enter explicit Id values into your table even if auto identity on column is set. (Though not a good idea to use always but its good for fixes)
SET IDENTITY_INSERT dbo.YourTableName ON;
GO
Then after each table's inserts:
SET IDENTITY_INSERT dbo.YourTableName OFF;
GO

Related

How do I use Data Anotations to create a relationship between these tables?

My question is how do I create a relationship between two tables that have nonstandard column names using data anotations?
My business object is a "Rule". Each Rule has an optional "Client".
Diagram above shows PK and FK.
Here's what I tried - I didn't get any errors but I'm not seeing the Client properties in my app.
Imports System.ComponentModel.DataAnnotations
Imports System.ComponentModel.DataAnnotations.Schema
Partial Public Class Rule
<Key>
Public Property FWAClientHandling As Integer 'PK
<ForeignKey("Client")>
Public Property iClientID As Integer 'FK
Public Property Client As Client 'Child object
End Class

EF Table with multiple references to same Table

I have a Database First Entity Framework Model
Tables:
1) User
Id
2) Article:
Id
UserCreated > Ref to User last edited User
UserChanged > Ref to User which created the Article
Enity Framework is Generating a Model like this
Partial Public Class Article
Public Property ID As Integer
Public Property UserCreated As Integer
Public Property UserChanged As Integer
Public Overridable Property User As User
Public Overridable Property User1 As User
End Class
Now I have another table like Vouchers also with UserCreated and UserChanged but names User1 and User.
Is there any way to specific the name of the property without changing the class itself because its generated from the Database.
You can use a DataAnnotation on the UserCreated property to specify the foreign key name:
[ForeignKey("UserCreated")]
http://msdn.microsoft.com/en-gb/data/gg193958.aspx
You can easily change the property name for User1 to any other name using the edmx-Designer.
But you should be aware that User is the reference to the column UserCreated. Because it may be that User references to UserChanged. You should check that. The best way is to check the name of the relationship. Therefore you need to give the relationship a meaningful name that you are able to distinguish them. Then you can right click on the relationship line and retrieve the relationship name.

NHibernate 3.2 mapping by convention generating an unnecessary foreign key column

I have a couple of classes that look like this:
public class Client
{
public int Id {get;set;}
public string Name {get;set;}
}
public class User
{
public int Id {get;set;}
public string Email {get;set;}
public Client Client {get;set;}
}
I'm using ConventionModelMapper and SchemaUpdate from NHibernate 3.2 to generate the schema in my SQL Server database and I want the Client property of the User class to be mapped to a ClientId column with foreign key. My convention code looks like this:
mapper.AfterMapManyToOne += (inspector, member, map) =>
{
map.Column(member.LocalMember.Name + "Id");
// ...
};
This works, in that I get a column ClientId that is mapped as a foreign key, but I also end up with a Client column that is also mapped as a foreign key. It seems that NHibernate is treating the Client property as both a standard Property (and thus generating the Client column for it), and also a ManyToOne property (resulting in the additional ClientId column). How can I prevent the Client column from being generated
I have just copied your EXACT code and, after making the properties virtual, the behavior is the expected (there's a single column, ClientId)

Fluent NHibernate Duplicate Columns

I am having some redundant primary key issues.
I have an Item which contains many reports. I have mapped them as shown below. I can do Session.QueryOver(Of Item).List and there are no extra columns generated. I can also do Session.QueryOver(Of Report).List and there are no extra columns generated.
However, once I try to traverse the relationship from Item to Reports, I get the SQL query shown below. Can anyone tell me why? Thanks in advance!
Item Mapping:
Public Class ItemMapping
Inherits ClassMap(Of Item)
Public Sub New()
Table("Items")
Id(Function(x) x.ItemID)
HasMany(Function(x) x.Reports).KeyColumn("ItemID").Inverse().Cascade.All()
End Sub
End Class
Report Mapping:
Public Class ReportMapping
Inherits ClassMap(Of Report)
Public Sub New()
Table("Reports")
Id(Function(x) x.ReportID)
References(Function(x) x.Item).Column("ItemID")
Map(Function(x) x.ReportName)
End Sub
End Class
SQL Result:
SELECT repor0_.ItemID as ItemID1_,
repor0_.ReportID as Rep1_1_,
repor0_.ReportID as Rep1_4_0_,
repor0_.ReportName as Rep2_4_0_,
repor0_.ItemID as ItemID4_0_ FROM dbo.Reports repor0_ WHERE repor0_.ItemID=#p0;#p0 = 1266 [Type: Int32 (0)]
This is not a bug according to nhusers group. Apparently NHibernate uses one column for the ID and second one for the foreign key. There are also other cases where some of the columns are sent twice. According to the thread it is not worth it to optimize the extra column away because it doesn't generate additional I/O usage and in normal cases the extra column does not cause too much network traffic.
I do not see 'reportdate' anywhere in your presented mapping files, while it is there in your query therefore I suspect there are other mappings in your project that we currently do not see?

fluent nhibernate auto increment non key (Id) property

Is it possible to have an integer property of a class auto increment managed by the database but not be a primary key (or Id as NHibernate refers to them)? I'm having trouble finding examples of how to do this. Any help would be appreciated. Thanks.
Two options.
if the database is 100% responsible for this you just need to tell NHibernate that the property is generated and not to include it in any updates/isnerts. The downside is that NH will need to do an additional select to keep the value fresh in memory.
< property name="Foo" generated="always" update="false" insert="false" />
if the database is not responsible and you just want to have this done automatically you can use an interceptor to set the value to 1 on an insert and to increment it by 1 on an update.
http://www.nhforge.org/doc/nh/en/index.html#objectstate-interceptors (11.1 - Interceptors)
You would override OnSave() to find the property and set the initial value and then override OnFlushDirty() to find the property property and increment.
Edit:
I'm an idiot, didn't notice you said Fluent NHibernate.
Edit #2:
I think you might also be interested in using this column as a versioning?
< version name="Foo" generated="always" />
This works for me:
public class Potato
{
public virtual Guid Id { get; protected set; }
public virtual int LegacyId { get; protected set; }
}
public class PotatoMap : ClassMap<Potato>
{
public PotatoMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.LegacyId).CustomSqlType("INT IDENTITY(1,1)").Not.Nullable().ReadOnly().Generated.Insert();
}
}
Basically, the integer is set to be generated by the database and NHibernate is instructed to retrieve it on inserts.
It is important to note that the mapping is only half of the answer, and it will not work if the column is not created as an IDENTITY. CustomSqlType is added to the mapping with the purpose of creating the proper sql when generating the tables with SchemaExport. This is the generated sql:
create table [Potato] (
Id UNIQUEIDENTIFIER not null,
LegacyId INT IDENTITY(1,1) not null,
primary key (Id)
)
On the other side, ReadOnly and Generated.Insert() will tell NHibernate that the value is autogenerated by the database only on inserts, and therefore it has to query the database for the value at every insert.
Note that I only tested this with Sql Server. The custom type will probably change or may not be available in other databases.