I have two entities in parent/child relationship. In addition, parent contains a reference to a "main" child, so the simplified model looks like this:
class Parent
{
int ParentId;
int? MainChildId;
}
class Child
{
int ChildId;
int ParentId;
}
The problem I am experiencing now is that EF does not seem to be able to handle creation of both Parent and Child in a single operation. I am getting an error "System.Data.UpdateException: Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values."
MainChildId is nullable, so it should be possible to generate a parent, a child and then update a parent with the newly generated ChildId. Is this something that EF does not support?
No, it's supported. Try it with a GUID key or an assignable sequence. The error means exactly what it says it does: The EF can't figure out how to do this in one step. You can do it in two steps, though (two calls to SaveChanges()).
I had this exact issue. The apparent "Circular reference" is simply good database design. Having a flag on the child table like "IsMainChild" is bad design, the attribute "MainChild" is a property of the parent not the child, so an FK in the parent is appropriate.
EF4.1 needs to figure out a way to handle these type of relationships natively and not force us to redesign our databases to accommodate deficiencies in the framework.
Anyhow my workaround is to do it several steps (like you might when writing a stored procedure to do the same) the only wrinkle is to get round the change tracking on the context.
Using context As New <<My DB Context>>
' assuming the parent and child are already attached to the context but not added to the database yet
' get a reference to the MainChild but remove the FK to the parent
Dim child As Child = parent.MainChild
child.ParentID = Nothing
' key bit detach the child from the tracking context so we are free to update the parent
' we have to drop down to the ObjectContext API for that
CType(context, IObjectContextAdapter).ObjectContext.Detach(child)
' clear the reference on the parent to the child
parent.MainChildID = Nothing
' save the parent
context.Parents.Add(parent)
context.SaveChanges()
' assign the newly added parent id to the child
child.ParentID = parent.ParentID
' save the new child
context.Children.Add(child)
context.SaveChanges()
' wire up the Fk on the parent and save again
parent.MainChildID = child.ChildID
context.SaveChanges()
' we're done wasn't that easier with EF?
End Using
Both EF and LINQ to SQL have this problem of not being able to save circular references, even though they could be a lot more helpful by just encapsulating 2 or more SQL calls in a transaction behind the scenes for you instead of throwing an Exception.
I wrote a fix for this in LINQ to SQL but haven't gotten around to doing so in EF yet, because I've just been avoiding circular references in my db design for the time being.
What you can do is create a helper method that sets aside circular references, run that before calling SaveChanges(), run another method that puts the circular references back in place, and call SaveChanges() again. You can encapsulate all of that in a single method, maybe SaveChangesWithCircularReferences().
To put the circular references back, you need to track what you removed and return that log.
public class RemovedReference() . . .
public List<RemovedReference> SetAsideReferences()
{
. . .
}
So basically the code in SetAsideReferences is hunting down circular references, setting aside one half in each case, and recording those in a list.
In my case I created a class that stored the object, the property name, and the value (another object) that was removed, and just kept these in a list, like so:
public class RemovedReference
{
public object Object;
public string PropertyName;
public object Value;
}
There's probably a smarter structure to accomplish this; you could use a PropertyInfo object for example instead of a string, and you might cache the type to cheapen the second round of reflection.
This is an old question but still relevant with Entity Framework 6.2.0. My solution is three-fold:
Do NOT set the MainChildId column as HasDatabaseGeneratedOption(Computed) (this blocks you from updating it later)
Use a Trigger to update the Parent when I'm inserting both records simultaneously (this isn't a problem if the parent already exists and I'm just adding a new child, so be sure the Trigger accounts for this somehow - was easy in my case)
After calling ctx.SaveChanges(), also be sure to call ctx.Entry(myParentEntity).Reload() to get any updates to the MainChildId column from the Trigger (EF won't automatically pick these up).
In my code below, Thing is the parent and ThingInstance is the child and has these requirements:
Whenever a Thing (parent) is inserted, a ThingInstance (child) should also be inserted and set as the Thing's CurrentInstance (main child).
Other ThingInstances (children) may be added to a Thing (parent) with or without becoming the CurrentInstance (main child)
This resulted in the following design:
* EF Consumer must insert both records but leave CurrentInstanceId as null but be sure to set ThingInstance.Thing to the parent.
* Trigger will detect if a ThingInstance.Thing.CurrentInstanceId is null. If so, then it will update it to the ThingInstance.Id.
* EF Consumer must reload/refetch the data to view any updates by the trigger.
* Two round-trips are still necessary but only one atomic call to ctx.SaveChanges is necessary and I don't have to deal with manual rollbacks.
* I do have an extra trigger to manage, and there might be a more efficient way to do it than what I've done here with a cursor, but I'll never be doing this in a volume where performance will matter.
Database:
(Sorry, not tested this script - just generated it from my DB and put it here due to being in a hurry. You should definitely be able to get the important bits out of here.)
CREATE TABLE [dbo].[Thing](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Something] [nvarchar](255) NOT NULL,
[CurrentInstanceId] [bigint] NULL,
CONSTRAINT [PK_Thing] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ThingInstance](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[ThingId] [bigint] NOT NULL,
[SomethingElse] [nvarchar](255) NOT NULL,
CONSTRAINT [PK_ThingInstance] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Thing] WITH CHECK ADD CONSTRAINT [FK_Thing_ThingInstance] FOREIGN KEY([CurrentInstanceId])
REFERENCES [dbo].[ThingInstance] ([Id])
GO
ALTER TABLE [dbo].[Thing] CHECK CONSTRAINT [FK_Thing_ThingInstance]
GO
ALTER TABLE [dbo].[ThingInstance] WITH CHECK ADD CONSTRAINT [FK_ThingInstance_Thing] FOREIGN KEY([ThingId])
REFERENCES [dbo].[Thing] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[ThingInstance] CHECK CONSTRAINT [FK_ThingInstance_Thing]
GO
CREATE TRIGGER [dbo].[TR_ThingInstance_Insert]
ON [dbo].[ThingInstance]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #thingId bigint;
DECLARE #instanceId bigint;
declare cur CURSOR LOCAL for
select Id, ThingId from INSERTED
open cur
fetch next from cur into #instanceId, #thingId
while ##FETCH_STATUS = 0 BEGIN
DECLARE #CurrentInstanceId bigint = NULL;
SELECT #CurrentInstanceId=CurrentInstanceId FROM Thing WHERE Id=#thingId
IF #CurrentInstanceId IS NULL
BEGIN
UPDATE Thing SET CurrentInstanceId=#instanceId WHERE Id=#thingId
END
fetch next from cur into #instanceId, #thingId
END
close cur
deallocate cur
END
GO
ALTER TABLE [dbo].[ThingInstance] ENABLE TRIGGER [TR_ThingInstance_Insert]
GO
C# Inserts:
public Thing Inserts(long currentId, string something)
{
using (var ctx = new MyContext())
{
Thing dbThing;
ThingInstance instance;
if (currentId > 0)
{
dbThing = ctx.Things
.Include(t => t.CurrentInstance)
.Single(t => t.Id == currentId);
instance = dbThing.CurrentInstance;
}
else
{
dbThing = new Thing();
instance = new ThingInstance
{
Thing = dbThing,
SomethingElse = "asdf"
};
ctx.ThingInstances.Add(instance);
}
dbThing.Something = something;
ctx.SaveChanges();
ctx.Entry(dbThing).Reload();
return dbThing;
}
}
C# New Child:
public Thing AddInstance(long thingId)
{
using (var ctx = new MyContext())
{
var dbThing = ctx.Things
.Include(t => t.CurrentInstance)
.Single(t => t.Id == thingId);
dbThing.CurrentInstance = new ThingInstance { SomethingElse = "qwerty", ThingId = dbThing.Id };
ctx.SaveChanges(); // Reload not necessary here
return dbThing;
}
}
Related
I have a typical 1-M-1 relationship; to keep it simple, lets deal with 3 tables only, but my real problem is more complex.
UsersTbl --< UserMenusTbl >-- MenusRefTbl
The MenusRefTbl is a reference table, which is pretty much static. To create a new user, I load up data into a newUser Parent Entity (class UsersTbl), and its child navigation property (class UsersMenuTbl).
Then I call
var savedUserEntity = dbCtx.UsersTbl.Add(newUser);
int rowsAffected = dbCtx.SaveChanges();
This inserts data in both Parent and Child table (UsersTbl, UserMenusTbl), and generates any ##identity primary/foreign keys in both tables automatically; In effect, the LHS variable savedUserEntity is now refreshed to contain the auto-generated identities.
However, the navigation property for the 3rd table (MenusRefTbl) remains null;
For example,
savedUserEntity.UserMenusTbl.MenusRefTbl = null;
How do I fetch the 3rd TABLE data into my object savedUserEntity ?
I've seen a few methods like .Reload(), .LoadAsync() but they don't seem to work with navigation properties (multi-levels of related tables), or apply in my case.
So am I stuck with re-issuing a new query from scratch using a new context?
What i have done using the same context:
var savedUserEntity = dbCtx.UsersTbl.Add(newUser);
int rowsAffected = dbCtx.SaveChanges();
rtnUserEntity = dbCtx.UsersTbl
.Include(um => um.UserMenusTbl.Select(m => m.MenusRefTbl))
.Where(u => u.userID == savedUserEntity.userID) //identity after Save
.Single(); //rtn single record
I am using Entityframework 6, I am trying to insert a parent-child kind of data in the database.
I am using Entityframework.BulkInsert to insert data. I have autoIncrement int primary key in all the tables
My object is as follows :
var parentObjects= new List<parentObject>();
var childObjects= new List<childObject>();
for (int i = 0; i <= 100; i++)
{
var parentObj= new parentObject()
{
Name="p1",
Address="a1"
};
childObjects= SeedInitializer.ChildItems.OrderBy(x => new Random().Next()).Take(2).ToList();//this gets 2 child objects
foreach (var childObj in childObjects)
{
childObj .ParentObject= parentObj;
//childObj .CommissionPlanId = i; //tried this still not working
parentObj.ChildObjects.Add(childObj );
}
parentObjects.Add(parentObj);
}
//when I do a quickwatch on parentObjects, i see child objects in each parentObject, but
//with the last id of parentObject
context.BulkInsert(parentObjects, 1000);
context.SaveChanges();
On save only 2 records are created in the childObject are created with a wrong parentObject id i.e. 0
I am not able to understand why child items are not getting created, while parent objects are getting created. Can someone help me understand where I am doing the mistake ?
Disclaimer: I'm the owner of EntityFramework.BulkInsert
You cannot.
This feature has never been implemented.
Disclaimer: I'm the owner of Entity Framework Extensions
However, this new library (not free), can easily handle this kind of scenario.
The BulkSaveChanges work exactly like SaveChanges (handle parent/child) but way faster!
All methods are supported:
Bulk SaveChanges
Bulk Insert
Bulk Delete
Bulk Update
Bulk Merge
Example
// Easy to use
context.BulkSaveChanges();
// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);
I do not think there is an easy way to accomplish this task, because in order to insert the children, you have to actually finish inserting the parents and get their ids. Normal EF inserts have the advantage that each INSERT will also embed a SELECT to fetch just generated identifier, so that it can use to push it for children (if any).
One possible solution is the following:
Add a Guid RefProperty to the ParentObject type which is also persisted
Add a Guid BatchId to the ParentObject type which is also persisted
Add a Guid RefProperty to the ChildObject type which is not persisted
Save the whole structure by using the following (mainly pseudocode) sequence
var batchId = new Guid();
parentObjects.ForEach(item => item.BatchId = batchId);
// set RefProperty for all parents and children to reflect proper parentation
TransactionScope scope = null;
try
{
context.BulkInsert(parentObjects, 1000);
var newParents = context.ParentObjects.Where(_ => _.BatchId = batchId);
var refPropMap = newParents.ToDictionary(_ => _.RefProperty, _ => ParentId);
var childObjects.ForEach(item => item.ParentId = refPropMap[item.RefProperty]);
context.BulkInsert(childObjects, 1000);
DataAccess.SaveChanges();
scope.Complete();
}
catch (Exception exc)
{
scope?.Dispose();
}
Note: this is not tested
This is quite ugly, but it should do the trick: minimize round-trips to SQL Server and still be one single transaction.
In order to make the SELECT faster, an index on ParentObject table should be placed on BatchId including (covering) its key.
Alternative: change design for these tables to not use auto-increments, but UNIQUEIDENTIFIER columns. This way, all identifiers can be set before making the inserts.
In EF4 loading an entity from the db and setting its property to the same value as it had previously would still cause an update to be issued to the db.
In EF6, the entity seems to be aware that property value has not changed and so does not cause an update to be issued to the DB.
Is it possible to get the EF4 behavior in EF6?
What I have tried:
Set "context.Configuration.AutoDetectChangesEnabled = false;". This did not work.
Hail Mary: context.Configuration.ValidateOnSaveEnabled = false; this also did not work.
((IObjectContextAdapter) context).ObjectContext.ContextOptions.UseLegacyPreserveChangesBehavior = true; Did not work
The reason I need the old EF4 behavior is because the code used to depend on some triggers to update fields (ModifiedDate) and previously EF4 would always cause a save and now EF6 doesnt and this will cause a major regression head-ache!
Some code that I used to test this:
public void UpdateScenarioWithNoChangesCausesEfToNotPersistChanges()
{
using (
TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
{
IsolationLevel = IsolationLevel.ReadCommitted
}))
{
using (EnterpriseModel context = new EnterpriseModel())
{
//context.Configuration.AutoDetectChangesEnabled = false; //did not work
//context.Configuration.ValidateOnSaveEnabled = false; //did not work
//((IObjectContextAdapter) context).ObjectContext.ContextOptions.UseLegacyPreserveChangesBehavior = true; //did not work
Guid id = new Guid("3321dbaf-c55e-e411-80cf-00155d0d70c0");
var efScenario = (from s in context.Scenario
where s.ScenarioId == id
select s).First();
DateTime modifiedDateBeforeChanges = efScenario.ModifiedDate;
//just setting the value back to itself.
efScenario.ModifiedBy = efScenario.ModifiedBy;
context.SaveChanges();
//ef scenario object's ModifiedDate is set as a Computed
DateTime modifiedDateAfterChanges = efScenario.ModifiedDate;
//There is a trigger on Updates that sets the modifiedDate in the database.
//also ModifiedDate is set as a computed column.
//the following passes for EF4 and fails for EF6.
//If in EF6 i do make a change to efScenario.ModifiedBy = efScenario.ModifiedBy;
//then EF6 works!
Assert.AreNotEqual(modifiedDateBeforeChanges, modifiedDateAfterChanges);
}
}
}
What has worked:
I can change the ModifiedDate column to some new value and that causes EF to detect a change and causes a save. The trigger updates the modified date and then because the column is marked as computed, EF retrieves the value. (DONT LIKE! as I will have to go through every method that calls SaveChanges and make sure every entity that used to previously get updated, is being updated with a new ModifiedDate value.
Calling context.Entry(efScenario).State = EntityState.Modified; just before calling SaveChanges. This is no better than (1), in my opinion. And I probably would go with 1 for now.
My ideal solution:
A setting that I can toggle in EF that will allow me to get the previous behavior of EF4.
Bonus Question:
When did this behavior change in EF? I cant seem to find any document regarding this change!
Table Structure
CREATE TABLE [dbo].[Scenario](
[ScenarioId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Scenario_ScenarioId] DEFAULT (newsequentialid()),
[Name] [varchar](200) NOT NULL,
[ModifiedBy] [varchar](100) NOT NULL,
[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_Scenario_ModifiedDate] DEFAULT (getdate()),
CONSTRAINT [PK_Scenario] PRIMARY KEY CLUSTERED
(
[ScenarioId] 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
CREATE TRIGGER [dbo].[trUpdateModifiedDateScenario]
ON [dbo].[Scenario]
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
UPDATE a SET a.[Name]=b.[Name]
, a.[ModifiedBy]=b.[ModifiedBy]
, a.[ModifiedDate]=GETDATE()
FROM [dbo].[Scenario] a
INNER JOIN inserted b
ON a.[ScenarioId]=b.[ScenarioId]
END;
GO
You should be able to tell EF the model changed:
var efScenario = (from s in context.Scenario
where s.ScenarioId == id
select s).First();
context.Entry(efSCenario).State = EntityState.Modified;
context.SaveChanges(); //Should hit the database, it's marked as modified.
MSDN DbContext.Entry()
MSDN EntityState
How to revert back to Ef4 behavior?
I don't believe there is some global way to revert the behavior, you are going to have to manually do this.
In my application, the interface allows the user to create and delete entities in an Entity Framework model. All changes are added to the ObjectContext, and saved only when the user selects "Save".
My question is best asked by means of the following simple example:
I have a Foreign Key relation between two entity types, which I will call Parent and Child here. The database, in SQLite, is declared as follows:
CREATE TABLE Parents (ID INTEGER PRIMARY KEY);
CREATE TABLE Children
(
ID INTEGER PRIMARY KEY,
ParentID INTEGER NOT NULL
CONSTRAINT FK_ChildrenToParents REFERENCES [Parents](ID)
ON DELETE CASCADE ON UPDATE CASCADE
)
I then build an Entity Framework model on that database, and execute the following actions against it (see code below):
Create a Parent
Save
Delete the Parent
Create a new Parent with the same ID number as the original
Create a Child and provide it with the new Parent's ID number
Save (Fails)
demoDBEntities entities = new demoDBEntities();
Parent originalParent = new Parent { ID = 1 };
entities.Parents.AddObject(originalParent);
entities.SaveChanges(); // First Save
entities.Parents.DeleteObject(originalParent);
Parent newParent = new Parent { ID = 1 };
entities.Parents.AddObject(newParent);
Child newChild = new Child { ID = 2, ParentID = 1 };
entities.Children.AddObject(newChild);
entities.SaveChanges(); // Second Save
I get the following error on the second call to SaveChanges():
"Unable to insert or update an entity because the principal end of the 'demoDBModel.FK_Children_0_0' relationship is deleted."
It seems the problem is that the Entity Framework links the new Child item to the originalParent item, which is then deleted and replaced by the newParent item. This might sound conceited, but happens quite naturally in my application.
Is there any way for me to work around this problem?
PS: I know it's bad practice to re-use ID numbers of DB entries - however, in my case the ID numbers are Asset numbers, which could theoretically be reused. That said, the above scenario typically happens if the client creates a faulty Parent, then deletes it, recreates it, and then creates the Child item.
Instead of setting the foreign key property ParentID you could try to set one of the navigation properties (you must have at least one) and use only one call to AddObject to add the complete object graph to the context:
Either:
//...
entities.Parents.DeleteObject(originalParent);
Child newChild = new Child { ID = 2 };
Parent newParent = new Parent { ID = 1, Children = new List<Child>{ newChild } };
entities.Parents.AddObject(newParent);
entities.SaveChanges();
Or:
//...
entities.Parents.DeleteObject(originalParent);
Parent newParent = new Parent { ID = 1 };
Child newChild = new Child { ID = 2, Parent = newParent };
entities.Children.AddObject(newChild);
entities.SaveChanges();
I'm having the same problem that a few of you have had - when trying to insert a new object, EF inserts null values for some of their properties, and the insert fails.
First let me describe the structure of our DB. Its an event management system, in which each event needs to be associated with a practice group, stored in a cache table but ultimately fetched from Active Directory. I manually created the join table - is that a problem? Anyway, so Event has a foreign key pointing to EventPracticeGroup, which has a foreign key pointing to PracticeGroupCache. PracticeGroupCache also has a RegionId pointing to the Regions table.
The problem comes when trying to insert a new EventPracticeGroup object. Below is the code I'm currently using:
var eventPracticeGroup = new EventPracticeGroup();
if (TryUpdateModel<EventPracticeGroup>(eventPracticeGroup))
{
/*
var eventId = EventScheduleRepository.GetById(Convert.ToInt32(Request.QueryString["EventScheduleId"])).EventId;
eventPracticeGroup.Event = EventRepository.GetById(eventId);
eventPracticeGroup.PracticeGroupCache = PracticeGroupCacheRepository.GetById(eventPracticeGroup.PracticeGroupCacheId);
eventPracticeGroup.PracticeGroupCache.Region = RegionRepository.GetById(eventPracticeGroup.PracticeGroupCache.RegionId);
EventPracticeGroupRepository.Add(eventPracticeGroup);
*/
var eventId = EventScheduleRepository.GetById(Convert.ToInt32(Request.QueryString["EventScheduleId"])).EventId;
var theEvent = new Event() { Id = eventId };
EventRepository.Repository.UnitOfWork.Context.AttachTo("Events",theEvent);
var practiceGroupCache = new PracticeGroupCache() { Id = eventPracticeGroup.PracticeGroupCacheId };
practiceGroupCache.Region = new Region() { Id = eventPracticeGroup.PracticeGroupCache.RegionId };
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
EventPracticeGroupRepository.Add(eventPracticeGroup);
EventPracticeGroupRepository.Save();
return RedirectToAction("Index");
}
Anyway... as you can see, I've just tried using stub objects (no help), and I've also tried actually fetching and setting the objects. The error I get is:
Cannot insert the value NULL into column 'Name', table 'XXXX.dbo.Regions'; column does not allow nulls. INSERT fails. The statement has been terminated.
Obviously name is not a key field. I have checked the EDMX XML - only the Id (primary key columns) have StoreGeneratedPattern set to Identity, as they should (they are int32 identity columns). Not a single foreign key has StoreGeneratedPattern set to identity.
if I set Regions.Name to allow nulls, PracticeGroupCaches.Description throws the same error. It seems that every linked object gets set to null. I did have a look with the debugger, when I used the now commented out code, nothing was null and everything had a value. I even got the RegionRepository to return all of the regions, just to see if one of them somewhere had a null name. None did. There are only 2 in my test DB. Our object context is shared per HTTP request.
Please can anyone help. At this point I would settle for using the dirtiest workaround as long as it worked.
Regards,
Jonathan.
Look what happens when you call this line:
EventPracticeGroupRepository.Add(eventPracticeGroup);
You are adding a new eventPracticeGroup to the context. But eventPracticeGroup has the other related objects:
eventPracticeGroup -> PracticeGroupCache -> Region
And you create new objects for those:
var practiceGroupCache = new PracticeGroupCache() {
Id = eventPracticeGroup.PracticeGroupCacheId };
practiceGroupCache.Region = new Region() {
Id = eventPracticeGroup.PracticeGroupCache.RegionId };
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
When you add the eventPracticeGroup to the context this whole object graph gets added which means that EF considers all three objects as new which have to be added to the DB. Since you only fill the Id properties other string properties (like Name or Description) are null. Because they are not nullable in the database the INSERT command fails.
But I guess that you don't want to insert the related entities into the DB anyway but only the eventPracticeGroup. So you need to attach them to the context before you add the new object, something like:
var practiceGroupCache = new PracticeGroupCache() {
Id = eventPracticeGroup.PracticeGroupCacheId };
EventRepository.Repository.UnitOfWork.Context.AttachTo(
"PracticeGroupCaches",practiceGroupCache);
practiceGroupCache.Region = new Region() {
Id = eventPracticeGroup.PracticeGroupCache.RegionId };
EventRepository.Repository.UnitOfWork.Context.AttachTo(
"Regions",practiceGroupCache.Region);
eventPracticeGroup.PracticeGroupCache = practiceGroupCache;
EventPracticeGroupRepository.Add(eventPracticeGroup);
BTW as a side note: About this EventRepository.Repository.UnitOfWork.Context.XXX take a look at Ladislav Mrnka's answer here: EF 4.0 IsAttachedTo extension method and error An object with the same key already exists
Try to Add: [DatabaseGenerated(DatabaseGeneratedOption.None)]
On your Id field, Like:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
It seems like you already found the problem and the solution. In your DB schema it seems like the columns don't allow NULL values. So either change all these columns to allow NULL or don't insert null (this is what you currently are trying to do)