Database doubly connected relationship inserting problem - c#

I have two tables Plants and Information. For every plant there are many information, but for each plant there is a single MainInformation. So there is a one-to-many relationship and a one-to-one relationship between the two. The Information table has a PlantID and the Plants table has a MainInformationID. I want both fields in both tables not to be nulls. But now you can't insert either of the two records into their tables because each one requires their fields not be null, meaning they need the other record to be created first in order to create themselves. Perhaps this is not a good database design and something should be changed? (I am new to databases and entity framework)
I tried inserting into the database itself manually but I cant do it. I also tried this code with EntityFramework.
using (var context = new MyEntities())
{
var p = new Plant()
{
LatinName = "latinNameTest",
LocalName = "localNameTest",
CycleTime = 500
};
var i = new Information()
{
ShortDescription = "ShortDesc",
LongDescription = "LongDesc"
};
p.MainInformation = i;
i.Plant = p;
context.AddToPlants(p);
context.AddToInformation(i);
context.SaveChanges();
}

One of
The 1-1 FK column has to be NULL
The FK has to be disabled to allow parent insert before child
You have a single dummy Information row that is used by default in FL column
SQL Server does not allow deferred constraint checking without "code change" rights so even wrapping in a transaction won't work
Sounds like an EAV schema, which has other problems

You need to change the tables to allow for null. There is no other way to do this.

You may want to look at database transactions and how to use them with the Entity Framework. You can wrap both INSERTS into a single db transaction so the only results are both of them go in or neither go in.
Here is a link for transactions using EF. I didn't read through it but it seems to talk about them enough to get you started.

Related

Best practice for archiving an entity in EF code first

I'm trying to archiving an entity of a table. There are couple of ways to do this. One of them is to create IsArchived column and set it to true when an entity is deleted or put into history. One of the disadvantage of this design will make specified table so heavy.
Another way to do this is to create the duplication of the class of specified entity to be logged, make another table, and adding it to log table with the help of AutoMapper. In this case i need lots of duplicate classes of entities which needed to be archived.
Is there any other solutions for archiving specified entities?
The best way would be to add a nullable ArchivedTimeStamp column to the table. This way, it is possible to tell if the row was archived or not, and if so, when it was archived.
If you are worried about the table size, you can partition the table and automatically move the archived rows onto a secondary / slower physical disk. You can even partition it in such a way that only rows that was, let say, archived over a year ago, must be moved to the secondary partition.
More info on on SQL archiving using partitioning can be found on http://www.mssqltips.com/sqlservertip/2780/archiving-sql-server-data-using-partitioning/
You could have more than one database, with the same schema. You can then open a couple contexts, one to each database, using a different connection string. Query one, attach the entities to the other, and save.
I've never done this, but it should work. You might run into trouble since the entities are going to be attached to the source context and cannot be attached to the destination, but there are ways to unattach and reattach the entities.
I have implemented a soft delete for the purposes of undo. My answer shows how to overcome some of the problems normally associated with soft deletes - i.e. joins and indexes. It suits my purposes well. However, if it was used for archiving then the tables would grow forever.
Your other idea is to create duplicate classes and use automapper. That sounds like a lot of extra coding.
I think you could create a database with the same schema - except, perhaps, the primary keys would not be database generated, and foreign keys not enforced. Then override the delete so that the data is copied over.
Something like this:
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries()
.Where(p => p.State == EntityState.Deleted
&& p.Entity is ModelBase))//I have a base class for entities with a single
//"ID" property - all my entities derive from this
CustomDelete(entry);
return base.SaveChanges();
}
private void CustomDelete(DbEntityEntry entry)
{
var e = entry.Entity as ModelBase;
string tableName = GetTableName(e.GetType());
string sql = String.Format(#"INSERT INTO archive.{0} SELECT * FROM {0} WHERE ID = #id;
DELETE FROM {0} WHERE ID = #id", tableName);
Database.ExecuteSqlCommand(
sql
, new SqlParameter("id", e.ID));
entry.State = EntityState.Detached;
}
Note that in EF6 you could also override the delete by altering the sql in the migration file when mapping to stored procedures is used

EF 4.1 code first - How to update/delete many to many join table entries automatically

I have 2 entities, let's say, Trip and Activity. The relationship between them is many to many so a join table is created automatically by EF.
Entity Trip attributes:
-Id (PK) Generated by database
-Name
-Description
-Property1
-Property2
-Property3
Entity Activity attributes (this entity contains fixed records -read only-, no records are inserted here on performing inserts):
-Id (PK) Generated by database
-Name
-Description
-Cost
Join table contains 2 columns, that is, the IDs of the above entities, that are primary and foreign keys at the same time.
I have no problems inserting entries which automatically EF creates join table TripActivities and add entries successfully to it. Also entries are added successfully to entity Trip and it leaves unchanged entity Activity.
My problem is on updating entries, for example, - suppose user can modify information related to a trip from the GUI - so I take all the info from this GUI and I perform the following steps to update the existing trip:
Trip trip = Context.Trips.Find(id); // Search for the appropriate trip to update from Id
trip.Name = ObtainNameFromGUI();
trip.Description = ObtainDescriptionFromGUI();
trip.Property1 = ObtainProperty1FromGUI();
trip.Property2 = ObtainProperty2FromGUI();
trip.Property3 = ObtainProperty3FromGUI();
trip.Activities = new List<Activity>();
// From the GUI user selects from a checkbox list the activities associated to the trip
// So we read its Ids and from those ids we fetch from database the activities to obtain
// the info related to each activity selected in the GUI. This is all done inside the
// below method.
List<Activity> activities = this.ObtainActivitiesSelectedFromGUI();
// If no activites selected (=null) I want EF automatically deletes the entries in the
// joined table for this trip. And of course, if there are activities selected, EF
// should update the respectives entries in the joined table for this trip with the new
// ones.
if (activites != null)
{
activities.ForEach(a =>
{
trip.Activities.Add(a);
});
}
context.Trips.Add(trip);
context.SaveChanges();<br><br>
By doing this I want EF updates all the entities related (except Activity as it has fixed entries, must be kept unchanged), that is, Trip and the joined table automatically but it does not work: a new trip is created and more entries in the joined table (The only thing that is working is that entity Activity is kept unchanged as I want).
How to achieve this? I have spent a lot of hours trying to do this but without success...
Thanks in advance.
EDIT:
I have removed line:
context.Trips.Add(trip);
Now the results are:
-Entity Trip is correctly updated, no new records added which is Ok.
-Entity Activity is kept unchanged which is Ok.
-Join table: The old records for current trip being updated are not updated, instead new records are inserted for the current trip which is not correct.
I have used a different approach for similar scenario that I faced, which works well with Detached Entities. What I ended up was finding out which entities were added and which ones deleted by comparing GUI(detached entity) values to the database values. Here is the sample code that I have used. The entities in play are RelayConfig and StandardContact which have many to many relationship
public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
RelayConfig dbRelayConfig = context.RelayConfigs.Include(r => r.StandardContacts)
.Where(r => r.Id == relayConfig.Id).SingleOrDefault();
context.Entry<RelayConfig> (dbRelayConfig).CurrentValues.SetValues(relayConfig);
List<StandardContact> addedExposedContacts =
exposedContacts.Where(c1 => !dbRelayConfig.StandardContacts.Any(c2 => c1.Id == c2.Id)).ToList();
List<StandardContact> deletedExposedContacts =
dbRelayConfig.StandardContacts.Where(c1 => !exposedContacts.Any(c2 => c2.Id == c1.Id)).ToList();
StandardContact dbExposedContact = null;
addedExposedContacts.ForEach(exposedContact => {
dbExposedContact = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
dbRelayConfig.StandardContacts.Add(dbExposedContact);
});
deletedExposedContacts.ForEach(exposedContact => { dbRelayConfig.StandardContacts.Remove(exposedContact);});
You will use something like this. Assuming that you will get the related objects from the UI and just you are going to update the same in the database, some thing like the following will work.
context.Products.Attach(product);
context.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);
context.ObjectStateManager.ChangeObjectState(product.ProductDescription, System.Data.EntityState.Modified);
context.ObjectStateManager.ChangeObjectState(product.ProductModel, System.Data.EntityState.Modified);
context.SaveChanges();
As you may see here, we are setting the EntityState as Modified which hints EF to perform update for the related tables too.
Please post back your queries or any issues that you may encounter in this implementation.

How does the EF store relationship inside SQL Server Express? (very confused)

I have a question regarding the way the Entity Framework stores relationships between objects inside SQL Server Express 2008 as I'm pretty confused right now.
I'm working on an WPF/MVVM application using EF. For the sake of simplicity, I'm gonna use an example.
Lets say I have two tables in SQL Server, Customer and Orders. Customer has a primary key ID (uniqueidentifier) and Orders does have one too. Now Orders does also have a column called CustomerId (uniqueidentifier) on which I define a relationship to the Customer.ID column.
These tables map to Entity Framework objects Customer and Order.
What I usually do when creating a new Order would be this:
Order newOrder = Context.CreateObject<Order>();
newOrder.Id = Guid.NewGuid();
newOrder.CustomerId = customer.Id;
In this case, in the database (after saving the context) all the columns in Orders are filled with data.
Now this time I did this:
Order newOrder = Context.CreateObject<Order>();
newOrder.Id = Guid.NewGuid();
newOrder.Customer = customer; //so I'm assigning the Customer object to the relationship, not the ID
When doing it this way, I would also expect that in the database, after saving the context, the column Orders.CustomerId would have a value (the Customer's GUID). However, in my case, it does NOT. However, when I navigate the Customers collection in my WPF application, all the Orders appear under the right Customer. (I did restart the application multiple times, so the context is newly created). Also tested on another machine. So there is no cache thingie.
So I was wondering, how can EF know which Order belongs to which Customer even though the database does not hold the necessary information inside its table's columns? Or is there some place else where this info is stored automagically?
I am very very confused as of right now.

Adding related items using Linq to SQL

I have a database with 'transactions' and 'transaction_lines'. A transaction has the basic shared details, and the transaction lines holds the values of components that make up the transaction. In traditional SQL, I'd use a SQL Transaction (Sorry, we have an ambiguous word now...) and then I'd INSERT INTO Transaction ... get the IDENTITY key value from the new row in the transaction table, then insert into my transaction_line table, using the identity column from the Transaction table as the foreign key.
Is there a good way to do this with linq?
Here's what I have so far:
account_transaction ac = new account_transaction
{
transaction_date = DateTime.Now,
is_credit = isCredit,
account = (db.accounts.FirstOrDefault(a => a.account_id == accountid))
};
db.AddToaccount_transaction(ac);
db.SaveChanges();
I think inbetween the 'AddToaccount_transaction(ac)' and the 'db.SaveChanges()', I need to add my transaction_lines.
You should just be able to create new transaction_line objects and set the foreign entity to ac. In LINQ-to-SQL, you work with entity objects instead of explicit keys. By setting the entity object to the ac object you will instruct the layer to determine what the key is and set it for you.
Answer above is correct but I would wrap it all in a TransactionScope. That way if any part of that query fails it will roll back the transaction. Just remember to call the scope.Complete() method prior to closing connection.
http://msdn.microsoft.com/en-us/library/ms251686(VS.80).aspx

Entity Framework Many-To-Many with additional field on Joining Table

I have an entity context that includes three tables. The first is a table that contain products, the second contains recipes. The joining table has fields for IDs in both the products and recipes table as well as a 'bit' field called 'featured'.
I've searched and found no example on how to insert only how to select against this type of scenario.Does anyone have any suggestions on how this can be done? Thanks in advance for any help.
I didn't do C# for a while, so I am not sure my syntax is valid, anyway this should be the idea:
Products product = new Products { Blah, Blah, Blah };
bool flag = false;
for (int i = 0; i < 5; i++)
{
Products_Receipes pr = new Products_Receipes
{ Products = product, IsFeatued = flag };
pr.Receipes.Add(new Receipes());
pr.Receipes.Add(new Receipes());
flag = !flag;
}
Context.SaveChanges();
And if the above doesn't work, then let me just tell you that you have to create the main item (either Products or Receipes), then when you create the Products_Receipes set it's Products/Receipes property to the above (or by Products.Pruducts_Receipes.Add(pr)), then add the other side of the relation the same way.
An observation is that your diagram is structured more like a DB schema than an entity diagram. Entities should be designed to meet the business needs independent of the data storage structure so you can use any DB to store the data.
I believe you can remove the "Link" entity and set up a one-to-many or many-to-many associations between Products and Recipes. Then setup your DB schema w/ the link table and do the Table Mapping accordingly.

Categories