EF ignores DatabaseGeneratedOption.None - c#

I am using EF 6.1.3 Code First, but without migrations as the database already exists. I have an entity SRReports with the following property:
[Key, Required]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public int FRID { get; set; }
Entity Framework ignores the DatabaseGeneratedOption.None and sends TSQL to the server assuming FRID is autogenerated. The entity is assigned a value for FRID but entity framework ignores it and assumes that is autogenerated. (this is confirmed by checking a TRACE of what is sent to the server). The exception message is:
Message=Cannot insert the value NULL into column 'FRID', table 'RevLogon.dbo.SCIREPORTS'; column does not allow nulls. INSERT fails.
The statement has been terminated.
I tried using the fluent API instead of (and in addition to) the annotations.
modelBuilder.Entity<SCIREPORTS>()
.HasKey(e => e.FRID);
modelBuilder.Entity<SCIREPORTS>()
.Property(e => e.FRID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
But then I get the error when I query the table:
SCIREPORTS sr = mydb.SCIREPORTS.Where(s => s.FRID == FRID ).FirstOrDefault();
I get the following error:
System.MissingMethodException was caught
HResult=-2146233069
Message=Method not found: 'System.Data.Entity.ModelConfiguration.Configuration.PrimitivePropertyConfiguration System.Data.Entity.ModelConfiguration.Configuration.PrimitivePropertyConfiguration.HasDatabaseGeneratedOption(System.Nullable`1)'.*
I have uninstalled and reinstalled my EF package but haven't been able to solve this problem.
How can I get EF to insert the record with the ID?
Here is the basic code that inserts the record:
public SRUserComp(string myemail, short mycounter, int myFRID, string myreptype, string mypassword)
{ email = myemail;
Counter = mycounter;
reptype = myreptype;
password = mypassword;
FRID = myFRID; }
public bool CreateSRRecord(DateTime repduedate,
short repnumber)
{BSRModel mydb = new BSRModel();
sr = new SCIREPORTS();
sr.FRID = FRID;
sr.Counter = Counter;
sr.Final = true;
sr.RepDueDate = repduedate;
mydb.SCIREPORTS.Add(sr);
mydb.SaveChanges();
return true; }
After the saveChanges statement I get the following statements from the sql profiler on the server:
INSERT [dbo].[SCIREPORTS]([Counter], [RepDueDate], [RepArrivalDate],
[SciAppDate], [Adminappdate], [legacyDate], [RepNumber], [Final],
[RepReminderID], [Notes], [HaimSaw], [ResAuthApprovDate])
VALUES (#0, #1, NULL, NULL, NULL, NULL, #2, #3, NULL, NULL, NULL, NULL)
SELECT [FRID]
FROM [dbo].[SCIREPORTS]
WHERE ##ROWCOUNT > 0 AND [FRID] = scope_identity()

Related

Code First EF Concurrency Token with Guid

I am trying to use a GUID as the concurrency token but every time I try to insert a record there is an exception about null value not being able to be added.
Generated SQL and Exception Message:
Failed executing DbCommand (4ms) [Parameters=[#p0='?' (DbType = Guid), #p1='?' (Size = 10) (DbType = AnsiString), #p2='?' (Size = 150) (DbType = AnsiString)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Application] ([Id], [Code], [Name])
VALUES (#p0, #p1, #p2);
SELECT [Version]
FROM [Application]
WHERE ##ROWCOUNT = 1 AND [Id] = #p0; System.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'Version', table 'MyCompany.dbo.Application'; column does not allow nulls. INSERT fails.
public class Application
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
// A concurrency token for use with the optimistic concurrency checking
public Guid Version { get; set; }
}
With the model Builder:
builder.Property(c => c.Version)
.IsConcurrencyToken()
.ValueGeneratedOnAddOrUpdate();
Basically, I need advice about what I am doing wrong.
There are few things I see that need correction.
The modelbuilder statement should be modified as below
modelBuilder.Entity<Application>().Property(app => app.Version).ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();
Bear in mind that there is no value generation strategy that is specified on Version property. When we generate a migration with this state, the generated Migration.cs file assigns a defaultValue new Guid("00000000-0000-0000-0000-000000000000")); inside of the Up() method. Below is an example
On the other hand, if you want a new Guid to be added each time you insert a new row into the table, you should use a computed field. Below two images show the structure of the Version property decorated with attributes and the generated Migration. Also, below line code needs to be added to mark the computation.
modelBuilder.Entity<Contact>().Property(t => t.Version).HasComputedColumnSql("NEWID()");
With the changes mentioned, you'll have a new Guid successfully generated for every row inserted.

Unusual behavior of Entity Framework

I have the following code in C#:
public int AddSynonymBL(String[] syns, String word, User user)
{
int dismissedCounter = 0;
foreach (var item in syns)
{
BusinessLayerStatus.StatusBL res = this.dataAccess.AddSynonymDA(item.Trim().ToLowerInvariant(), word.Trim().ToLowerInvariant(), user);
if (res == BusinessLayerStatus.StatusBL.SynonymNotAdded)
++dismissedCounter;
}
int numberOfFailures = dismissedCounter;
return numberOfFailures;
}
And the following code is for AddSynonymDA method:
internal BusinessLayerStatus.StatusBL AddSynonymDA(string synonym, string word, User user)
{
try
{
Synonym newSyn = new Synonym()
{
Meaning = synonym
};
//The following if means that the searched word does not exist int the Searched table
if (this.context.Users.Where(a => a.Mail.Equals(user.Mail)).FirstOrDefault().Searcheds.Where(b => b.RealWord.Equals(word)).Count() == validNumberForKeyValues)
{
this.context.Users.Where(a => a.Mail.Equals(user.Mail)).FirstOrDefault().Searcheds.Where(b => b.RealWord.Equals(word)).FirstOrDefault().Synonyms.Add(newSyn);
this.context.SaveChanges();
return BusinessLayerStatus.StatusBL.SynonymAdded;
}
else
return BusinessLayerStatus.StatusBL.SynonymNotAdded;
}
catch (Exception ex)
{
ExceptionAction(ex);
return BusinessLayerStatus.StatusBL.SynonymNotAdded;
}
}
I am using Entity Framework. I have a table which contains an Id, a word column. Both of them together have unique key constraint in the database. My main code is as follows:
public static void Main()
{
EngineEntities context = new EngineEntities();
BusinessLogic bl = new BusinessLogic();
String[] s = new String[] { "java", "DB" };
Console.WriteLine(bl.AddSynonymBL(s, "Java", new User() { Mail = "media" }));
}
When I add a value which does not exist in the table everything is fine but when I add a value which already exists in the table, calling this.context.SaveChanges(); in the AddSynonymDA method, always throws an exception which was for the previous first exception which caused the first exception and nothing is added to database even if they do not exist in the database. Why is that?
I get the following error which shows that Java already exists. The problem is that Java is for the first call, as the second call, I have passed DB not Java.
{"Violation of UNIQUE KEY constraint 'IX_Searched'. Cannot insert duplicate key in object 'dbo.Searched'. The duplicate key value is (java, 2).\r\nThe statement has been terminated."}
I suspect that you have not set a column to be an Identity column in your database
In other words when you are inserting an entity you need a column to be automatically incrementing.
The way I do this is for example using SQL server:
ALTER TABLE [User] DROP COLUMN [ID];
ALTER TABLE [User]
ADD [ID] integer identity not null;
If you do not have an ID column already you do not need the first line.
After this, update your EF model in your project by deleting the User table and right clicking and Updating Model from Database and select the table.
So now when you insert new entries in you EF model, the ID column will be automatically incremented and you won't get an error.
you must initially check whether the item exists or not, since you seem to have a unique constraint, then you should utilize the attributes of reference in your code .

Seed primary key in Entity Framework code first to 0 in SQL Server Compact Edition

I have this Entity Framework code first class:
public class ClientEvent
{
[Key]
public int? EventCode { get; set; }
public string Description { get; set; }
}
With this seed function for SQL Server Compact Edition:
protected override void Seed(ClientEventsContext context)
{
var clientEvent = new ClientEvent
{
EventCode = 0,
Description = "Test"
};
context.Events.Add(clientEvent);
base.Seed(context);
}
When I check the database table for ClientEvent after it runs, I see this entry:
EventCode | Description
---------------------------
1 | Test
Notice how the EventCode is 1? I would expect it to be 0. How can I seed this primary key to start at 0? I have tried using the code above, but even utilizing 0 itself sets the first entry to 1.
There is another question similar to this which works for SQL Server, but not SQL Server Compact Edition. I have tried using its suggested answer to set the initializer to 0:
context.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('ClientEvents', RESEED, 0)");
The problem with this is:
System.Data.SqlServerCe.SqlCeException: There was an error parsing the
query. [ Token line number = 1,Token line offset = 1,Token in error =
DBCC ]
Is there not a standard way of doing this with Entity Framework code first, irrelevant of the type of database being used?
You can use this statement with SQL Server Compact:
ALTER TABLE [MyTable] ALTER COLUMN [Id] IDENTITY (0,1)

Raw query to add/alter column of table using Entity Framework without migration

I have restricted access to SQL server database & I have to alter table from my MVC project. I have tried:
var db = MyDbContext.Create();
try
{
var res =
db.Speakers.SqlQuery("ALTER TABLE [dbo].[Speakers] ADD [LastName] [nvarchar](256) NULL");
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
its not throwing exception but not updating table. I have no idea whether Raw query allow alteration or not. But I just gave a try. Can any one tell how can I alter database?
Try this approach:
db.Database
.ExecuteSqlCommand("ALTER TABLE [dbo].[Speakers] ADD [LastName] [nvarchar](256) NULL");
Non-query commands can be sent to the database using the
ExecuteSqlCommand method on Database. For example:
using (var context = new BloggingContext())
{
context.Database.ExecuteSqlCommand(
"UPDATE dbo.Blogs SET Name = 'Another Name' WHERE BlogId = 1");
}
Note that any changes made to data in the database using
ExecuteSqlCommand are opaque to the context until entities are loaded
or reloaded from the database.
Entity Framework Raw SQL Queries
https://msdn.microsoft.com/en-gb/data/jj592907.aspx

StackOverflowException when call DataContext.SubmitChanges()

I am using Linq-To-SQL to perform inserts into a table that has the following definition (omitting some superfluous fields):
ID int not null
SourceName varchar(100)
Version int not null
TransactionID int not null
Xml nvarchar(max)
ID, SourceName, Version and TransactionID form the primary key for the table. There are no foreign keys or constraints.
I create a DataContext for my database and then create a new record. When I call SubmitChanges on my DataContext a StackOverflowException is thrown.
using (var ctx = new MyDataContext(connectionString))
{
var row = new MyTable
{
ID = 1
, SourceName = "foo"
, Version = 1
, TransactionID = 0 //this is the weird part - see below
, Xml = "some xml string"
}
ctx.MyTable.InsertOnSubmit(row);
ctx.SubmitChanges();
}
However, after lots of value substituting and trial and error the StackOverflowException does not get thrown if I change TransactionID to 1 (I initially assumed the Xml field was somehow overflowing).
I was using 0 just for the scenarios where for a transaction id could not be identified some reason.
I obviously googled this but the only related issue I found was caused by a foreign key relationship.
Anyone have any idea why this is happening? I have a work around but am curious what could be the cause.
I am using .Net 3.5 and SQL Server 2005.

Categories