Linq To Sql duplicate a row in update case - c#

I have a single entity that always duplicate a row when it needs to update:
protected static Task RegisterToDisc(Task task)
{
try
{
using (DataContext context = new DataContext())
{
//this will print an actual existing id from the db
_log.Debug(task.ID);
context.Tasks.InsertOnSubmit(task);
context.SubmitChanges();
}
}
catch(Exception e)
{
//...
}
return task;
}
When I print the id before the save, it is actually prints out an id that is really exists in the db.
this is the table:
CREATE TABLE [dbo].[TaskSet](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Message] [nvarchar](max) NOT NULL,
[Result] [nvarchar](max) NOT NULL,
[Status] [int] NOT NULL,
[Priority] [int] NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[DateTimeAsked] [datetime] NOT NULL,
[DateTimePerfomed] [datetime] NOT NULL,
[SessionID] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_TaskSet] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Edit
The task is comming from the database already, task.ID contains a number that is exists in the database, how come Linq inserts an entity with PK that is not null and in the db already.
in java hibernate you neet to context.insertOrUpdate(task); and it will decide what to do by the primary key.

InsertOnSubmit always marks the object for insertion. if you want to update the object u need to read it from database like
var objToUpdate = context.Tasks.SingleOrDefault(x=>x.Id == Id);
objToUpdate.Property1 = "updated value";
objToUpdate.Property2 = "updated value";
//do it for all properties that need updating
context.SubmitChanges();//since the object is tracked by context it will automatically generate sql to reflect update in db

Related

Code first from Database - Cannot insert the value NULL into column 'Id' but value actually is not null

I try to add new record :
entity.Id = Id;
_bdc.EquifaxAnswers.Add(entity);
_bdc.SaveChanges();
and Id has exactly defined as primary key and Id in code has value ( unique for table).
And EF create sql code for add record:
INSERT [dbo].[EquifaxAnswers]([FileName], [dtSend], [dtDateTime], [RecordsAll], [RecordsCorrect],
[RecordsIncorrect], [ResendedId], [dtEmailAbout], [StartDate], [EndDate])
VALUES (#0, #1, #2, NULL, NULL, NULL, NULL, NULL, #3, #4)
And as we can see there Id does not exist, so _bdc.SaveChanges();create Exception:
Failed in 25 ms with error: Cannot insert the value NULL into column 'Id', table 'Equifax.dbo.EquifaxAnswers'; column does not allow nulls. INSERT fails.
Primary key definition:
public partial class EquifaxAnswers
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
Why EF don't add Id to INSERT and how to resolve this problem ?
UPD:
Table definition script in database:
CREATE TABLE [dbo].[EquifaxAnswers](
[Id] [int] NOT NULL,
[FileName] [nvarchar](300) NOT NULL,
[dtSend] [datetime] NOT NULL,
[dtDateTime] [datetime] NULL,
[RecordsAll] [int] NULL,
[RecordsCorrect] [int] NULL,
[RecordsIncorrect] [int] NULL,
[ResendedId] [int] NULL,
[dtEmailAbout] [datetime] NULL,
[StartDate] [datetime] NULL,
[EndDate] [datetime] NULL,
CONSTRAINT [PK_EquifaxAnswers] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
You have specified DatabaseGeneratedOption.None
This means that EF is not expecting the database to generate the Id field, and that you should specify the Id field yourself.
If you want the database to generate the Id field automatically, then alter the column to be an IDENTITY type, and change the code to DatabaseGeneratedOption.Identity
Solution:
modelBuilder.Entity<EquifaxAnswers>()
.Property(a => a.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
If this doesn't work - just uninstall and install again all EF packages ( I don't know why - but this is work for me) for all dependent projects , latest stable version of course.
Reasons:
By convention, EF will assume that primary key properties are automatically generated. So we need to say EF that we will do it by our code. However,this is not clear why doesn't work DataAnnotations like this:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
but fluent API is working well. Perhaps the reason is that I use both.

How Can I Do Create Table by using sql query in NHibernate?

I have a dynamic table in my project, I doing mapping static table by using Nhibernate fluent API in the model solution. Dynamic table going to create at runtime. dynamic tables have dynamic columns. How can I do Create a dynamic table in NHibernate? thanks for help
CREATE TABLE [dbo].[Events](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[Quota] [int] NOT NULL,
[Description] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.Events] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
thanks for help.
I was already using Isession.CreateSqlQuery(sql) but not was working Create table
improved when replace code ' Isession.createSqlQuery(sql).executeUpdate()'

How can I check if the DateTimes of an item is within the range of two other dates?

I am a new ASP.NET developer and I have 2 inputs in a form as DateTimes; StartDate and EndDate. I want to make sure that both of them are within the StartDate and EndDate of the Parent from another table. The logic should be as following:
Check if the StartDate of the items comes before the EndDate.
Check if the StartDate & EndDate of the inserted item is within the range of the StartDate and EndDate in the Customers table
So how can I do this logic?
For your information, I have two tables in the database, namely; Customers and Items.Their schema are:
Customers Table:
CREATE TABLE [dbo].[Customers](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[Job] [varchar](50) NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Items Table:
CREATE TABLE [dbo].[Items](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Description] [varchar](50) NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[CustomerID] [int] NOT NULL,
CONSTRAINT [PK_Items] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Items] WITH CHECK ADD CONSTRAINT [FK_Items_Customers] FOREIGN KEY([CustomerID])
REFERENCES [dbo].[Customers] ([ID])
GO
ALTER TABLE [dbo].[Items] CHECK CONSTRAINT [FK_Items_Customers]
GO
My C# Code:
protected void btnSubmit_Click(object sender, EventArgs e)
{
DateTime startDate = Convert.ToDateTime(txtStartDate.Text);
DateTime endDate = Convert.ToDateTime(txtEndDate.Text);
if (DateTime.Compare(startDate, endDate) <= 0)
{
using (TestDBEntities1 TEntities = new TestDBEntities1())
{
var newItem = new Item
{
Name = txtName.Text,
Description = txtDesc.Text,
StartDate = startDate,
EndDate = endDate,
CustomerID = Convert.ToInt32(ComboBox1.SelectedValue)
};
TEntities.Items.AddObject(newItem);
TEntities.SaveChanges();
}
lblMessage.Text = "Successfully Added :)";
}
else
{
lblMessage.Text = "Error!!!";
}
}
NOTE: I am using LINQ for querying the database. I am only missing the part of doing the logic for checking if the StartDate & EndDate of the inserted item is within the Dates in the Customers table.
Explanation:
For example, let us assume we have StartDate#1 and EndDate#1 for an item that will be inserted. In the Customers table, I have StartDate#2 and EndDate#2. The logic should do the following:
check if the StartDate#1 comes before EndDate#1
Then, check if StartDate#1 and EndDate#1 are falling within the range of StartDate#2 and EndDate#2

EF ##ROWCOUNT > 0 leads to wrong upsert

I'm trying to update an existing in the DB entity (MamConfiguration_V1) call it Parent
I want to
1) add a reference (navigation) member to it (MamConfigurationToBrowser_V1) call it Child
2) I don't change the value of a unique property in the Parent entity. (Parent.Name)
I got the entity to update from the DB,
and using the same context (mMamDbEntities)
I add the reference member.
I don't change its Name property.
However I get a DB error, uniquness restriction violation
{"Violation of UNIQUE KEY constraint 'UQ_MamConfigurations_V1'. Cannot insert duplicate key in object 'dbo.MamConfiguration_V1'. The duplicate key value is (elad_14Apr_1315).\r\nThe statement has been terminated."}
I did DB sniffing and saw the generated code:
exec sp_executesql N'update [dbo].[MamConfiguration_V1]
set [Name] = #0, [Description] = #1, [StatusId] = #2, [Type] = #3, [UpdatedDate] = #4, [PercentageTraffic] = #5, [NumericTraffic] = #6
where ([ConfigurationId] = #7)
',N'#0 nvarchar(50),#1 nvarchar(200),#2 int,#3 int,#4 datetime2(7),#5 int,#6 int,#7 int',#0=N'elad_17Apr_1120_tmpToRemove_',#1=N'elad_22Apr_1120',#2=2,#3=0,#4='2013-04-23 11:17:25.4991650',#5=55,#6=-1,#7=32
//some more commands
exec sp_executesql N'insert [dbo].[MamConfiguration_V1]([Name], [Description], [StatusId], [Type], [CreatedDate], [UpdatedDate], [PercentageTraffic], [NumericTraffic])
values (#0, #1, #2, #3, #4, #5, #6, #7)
select [ConfigurationId]
from [dbo].[MamConfiguration_V1]
where ##ROWCOUNT > 0 and [ConfigurationId] = scope_identity()',N'#0 nvarchar(50),#1 nvarchar(200),#2 int,#3 int,#4 datetime2(7),#5 datetime2(7),#6 int,#7 int',#0=N'elad_17Apr_1120_tmpToRemove_',#1=N'elad_22Apr_1120',#2=2,#3=0,#4='0001-01-01 00:00:00',#5='0001-01-01 00:00:00',#6=55,#7=-1
I would have expected upsert to be ##ROWCOUNT = 0
What am I doing wrong?
My code and DB are:
public void SaveCofiguration(MamConfiguration_V1Ui itemUi)
{
var itemEf = mMamConfiguration_V1UiToEfConvertor.ConvertToNewEf(itemUi);
using (var maMDBEntities = new MaMDBEntities())
{
IDal<MamConfiguration_V1> mamConfigurationDal = mDalFactory.GetDal<MamConfiguration_V1>(maMDBEntities);
mamConfigurationDal.Save(itemEf);
}
}
public MamConfiguration_V1 GetById(object id)
{
id.ThrowIfNull("id");
int configurationId = Convert.ToInt32(id);
var result =
mMaMDBEntities.MamConfiguration_V1.SingleOrDefault(item => item.ConfigurationId == configurationId);
return result;
}
public MamConfiguration_V1 Save(MamConfiguration_V1 item)
{
item.ThrowIfNull("item");
var itemFromDB = GetById(item.ConfigurationId);
if (itemFromDB != null)
{
UpdateEfItem(itemFromDB, item);
// if (mMaMDBEntities.ObjectStateManager.GetObjectStateEntry(itemFromDB).State == EntityState.Detached)
// {
// mMaMDBEntities.MamConfiguration_V1.AddObject(itemFromDB);
// }
// Attached object tracks modifications automatically
mMaMDBEntities.SaveChanges();
return item;
}
private void UpdateEfItem(MamConfiguration_V1 itemFromDb, MamConfiguration_V1 itemFromUi)
{
itemFromDb.UpdatedDate = DateTime.Now;
itemFromDb.Description = itemFromUi.Description;
itemFromDb.StatusId = itemFromUi.StatusId;
itemFromDb.Name = itemFromUi.Name;
itemFromDb.NumericTraffic = itemFromUi.NumericTraffic;
itemFromDb.PercentageTraffic = itemFromUi.PercentageTraffic;
itemFromDb.Type = itemFromUi.NumericTraffic;
foreach (var item in itemFromDb.MamConfigurationToBrowser_V1.ToList())
{
if (itemFromUi.MamConfigurationToBrowser_V1.All(b => b.BrowserVersionId != item.BrowserVersionId))
{
mMaMDBEntities.MamConfigurationToBrowser_V1.DeleteObject(item);
}
}
for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++)
{
var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i);
var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId);
if (item != null)
{
// copy properties from element to item
}
else
{
element.Browser = mMaMDBEntities.Browsers.Single(browserItem =>
browserItem.BrowserID == element.BrowserID);
//element.MamConfiguration_V1 = itemFromDb;
//have also tried: element.MamConfiguration_V1 = null;
//element.MamConfiguration_V1Reference = null;
itemFromDb.MamConfigurationToBrowser_V1.Add(element);
}
}
}
Update:
mMaMDBEntities.SaveChanges(); throws the exception
These are the DB tables:
CREATE TABLE [dbo].[MamConfiguration_V1](
[ConfigurationId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Description] [nvarchar](200) NOT NULL,
[StatusId] [int] NOT NULL,
[Type] [int] NOT NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[UpdatedDate] [datetime2](7) NOT NULL,
[PercentageTraffic] [int] NOT NULL,
[NumericTraffic] [int] NOT NULL,
CONSTRAINT [PK_MamConfigurations_V1] PRIMARY KEY CLUSTERED
(
[ConfigurationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [SECONDARY],
CONSTRAINT [UQ_MamConfigurations_V1] UNIQUE NONCLUSTERED
(
[Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [SECONDARY]
) ON [SECONDARY]
GO
ALTER TABLE [dbo].[MamConfiguration_V1] WITH CHECK ADD CONSTRAINT [FK_MamConfiguration_V1_ConfigurationType_V1] FOREIGN KEY([StatusId])
REFERENCES [dbo].[MamConfigurationStatuses] ([StatusId])
GO
ALTER TABLE [dbo].[MamConfiguration_V1] CHECK CONSTRAINT [FK_MamConfiguration_V1_ConfigurationType_V1]
GO
ALTER TABLE [dbo].[MamConfiguration_V1] ADD CONSTRAINT [DF_MamConfigurations_V1_CreatedDate] DEFAULT (getdate()) FOR [CreatedDate]
GO
ALTER TABLE [dbo].[MamConfiguration_V1] ADD CONSTRAINT [DF_MamConfigurations_V1_UpdatedDate] DEFAULT (getdate()) FOR [UpdatedDate]
GO
CREATE TABLE [dbo].[MamConfigurationToBrowser_V1](
[MamConfigurationId] [int] NOT NULL,
[BrowserVersionId] [uniqueidentifier] NOT NULL,
[IsWhiteListed] [bit] NOT NULL,
[BrowserID] [int] NOT NULL,
[VersionNumberLowRange] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[VersionNumberUpperRange] [varchar](50) NULL,
CONSTRAINT [PK_MamConfigurationToBrowser_V1_1] PRIMARY KEY CLUSTERED
(
[BrowserVersionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [SECONDARY]
) ON [SECONDARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] WITH CHECK ADD CONSTRAINT [FK_MamConfigurationToBrowser_V1_Browsers] FOREIGN KEY([BrowserID])
REFERENCES [dbo].[Browsers] ([BrowserID])
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] CHECK CONSTRAINT [FK_MamConfigurationToBrowser_V1_Browsers]
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] WITH CHECK ADD CONSTRAINT [FK_MamConfigurationToBrowser_V1_BrowserVersion] FOREIGN KEY([MamConfigurationId])
REFERENCES [dbo].[MamConfiguration_V1] ([ConfigurationId])
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] CHECK CONSTRAINT [FK_MamConfigurationToBrowser_V1_BrowserVersion]
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] ADD CONSTRAINT [DF_Browser_V1_CreatedDate] DEFAULT (getdate()) FOR [CreatedDate]
GO
ALTER TABLE [dbo].[MamConfigurationToBrowser_V1] ADD CONSTRAINT [DF_Browser_V1_UpdatedDate] DEFAULT (getdate()) FOR [UpdatedDate]
GO
Update 2
I have tried #AzharKhorasany solution, but go the same error:
for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++)
{
var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i);
var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId);
if (item != null)
{
// copy properties from element to item
}
else
{
element.Browser = mMaMDBEntities.Browsers.Single(browserItem =>
browserItem.BrowserID == element.BrowserID);
element.MamConfigurationId = itemFromDb.ConfigurationId;
//element.MamConfiguration_V1 = itemFromDb;
//have also tried: element.MamConfiguration_V1 = null;
//element.MamConfiguration_V1Reference = null;
//mMaMDBEntities.AddToMamConfigurationToBrowser_V1(itemFromUi.MamConfigurationToBrowser_V1.ElementAt(0)); // add as inserted
itemFromDb.MamConfigurationToBrowser_V1.Add(element);
}
}

Weird behaviour in EF (possible bug)

I think I might have found a bug in Entity Framework.
I'm using Database First with MVC3.
I have the following table in my database:
CREATE TABLE [dbo].[InstructionStep](
[instructionID] [uniqueidentifier] NOT NULL,
[step] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[description] [nvarchar](max) NULL,
[recurrence] [numeric](18, 0) NULL,
[parameters] [nvarchar](50) NULL,
[secuence] [numeric](18, 0) NULL,
[time] [nvarchar](50) NULL,
CONSTRAINT [PK_InstructionStep] PRIMARY KEY CLUSTERED
(
[instructionID] ASC,
[step] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY
I'm using linq to EF to save/edit information into this table. The thing is... the "time" column, NEVER gets a value. I triple checked and the model DOES have a value for the time property of the object, but when I pass it to EF, it never makes it to the database. This is the code I use to create a new record:
using (Models.SAIMBehrEntities db = new Models.SAIMBehrEntities())
{
if (step.description != null)
step.description = step.description.ToUpper();
if (step.parameters != null)
step.parameters = step.parameters.ToLower();
db.InstructionSteps.AddObject(step);
db.SaveChanges();
}
this is the code I use to edit a record:
Models.InstructionStep s = db.InstructionSteps.Where(x => x.instructionID == stepM.instructionID && x.step == stepM.step).FirstOrDefault();
if (s != null)
{
s.parameters = stepM.parameters;
s.description = stepM.description;
s.recurrence = stepM.recurrence;
s.secuence = stepM.secuence;
s.time = stepM.time;
db.SaveChanges();
}
Everything else gets saved, except the "time" column. Now, I fired up sql profiler. This is the query generated by the create method:
exec sp_executesql N'insert [dbo].[InstructionStep]([instructionID], [description], [recurrence], [parameters], [secuence])
values (#0, #1, #2, #3, #4)
select [step], [time]
from [dbo].[InstructionStep]
where ##ROWCOUNT > 0 and [instructionID] = #0 and [step] = scope_identity()',N'#0 uniqueidentifier,#1 nvarchar(max) ,#2 decimal(18,0),#3 nvarchar(50),#4 decimal(18,0)',#0='9013B4B0-28FB-4C52-912D-3598A8E13880',#1=N'DEMO DESCRIPTION',#2=1,#3=N'none',#4=1
And this is the query generated by the update method:
exec sp_executesql N'update [dbo].[InstructionStep]
set [description] = #0, [recurrence] = #1, [parameters] = #2, [secuence] = #3
where (([instructionID] = #4) and ([step] = #5))
select [time]
from [dbo].[InstructionStep]
where ##ROWCOUNT > 0 and [instructionID] = #4 and [step] = #5',N'#0 nvarchar(max) ,#1 decimal(18,0),#2 nvarchar(50),#3 decimal(18,2),#4 uniqueidentifier,#5 decimal(18,0)',#0=N'DEMO DESCRIPTION',#1=1,#2=N'none',#3=1.00,#4='9013B4B0-28FB-4C52-912D-3598A8E13880',#5=1386
So... yeah. The "time" column gets selected after an update/insert. Why? beats me...
I tried changing the column name to "timestep" and worked correctly.
Is this a normal behaviour? am I just being plain stupid or is this a bug?
Thanks!

Categories