Entity framework update of row version in a predefined order - c#

I am using C#, EF and SQL Server and have few tables with parent-child relationship. There are more than 2 but in this example I will use only 2 for simplicity.
Table Book
Id
DateModified
RowVersion
Table Page
Id
BookId - this is foreign key to Book.Id
RowVersion
When any page/pages are updates I need to update DateModified in Book table.
We are using RowVersion to keep track of changes, since it's unique value I want to always be able to get the latest changes for each book by simply doing something like
SELECT * FROM Page
WHERE RowVersion > Book.RowVersion
But in order to do this I need to make sure that RowVersion in Book table is ALWAYS updated before RowVersions in Pages.
In my EDM layer I currently have something like this:
class Page
{
void OnPageChanged() //this is hooked to OnPropertyChanged
{
this.Book.UpdateDateModified(DataTime.Now);
}
}
Doing this results in page being updated first and its RowVersion is updated first too after the transaction commits. Which is not what I need.
Question, if I will move OnPageChanged() to be handling OnPropertyChanging event instead - will this guarantee the consistency? Is it OnPropertyChanged that dictates the order the updates happen in sql generated by EF? Any other suggestions for this case?

I don't think this is possible. I cannot try it now but I have real doubts that you can compare timestamps (RowVersion) in Linq query. It is mapped to byte array and byte array is not comparable. The order of operations in the database is absolutely out of your control. You cannot base your logic on expected order in which the entities will be updated. You can do it only if your pages and book will be saved by two different SaveChanges calls. In such case you cannot use OnPropertyChanges at all and you must handle Book change manually before you make any change to your pages.

Related

Reference Table through a variable in Entity Framework

I have 5 tables in database Table1, Table2 and so on [All tables have same column name or Table Definition]. I am using Entity Framework in MVC application and C#.
First creating an object of db of Database.
Getting table data as db.Table1.ToList();.
I want to do some thing like this.
list<string> TableNames = new list<string>();
db.TableNames[1].ToList();
Now I know this won't work but is there any way I can get data without hard coding the table names as my Project will deal with 100s of tables with same column names but different data.
This is a Project for a Hospital which will receive data from different locations. Lets say for location A I am expecting 100 cases a day and right now I have 10 locations. So if I combine all this data into one which means 1000 records each day in a single day therefore overtime searching through this table will become performance sensitive.
I am writing this for those who might occur into this same dilemma.....
I had reference a table through EF so the classes got generated into the Model.
Lets say I have 3 tables of same schema tbl_Loc1, tbl_Loc2 and tblLoc3.
public void getDataFromTable(string TableName)
{
using(var ctx = new DBEntities())
{
string query ="Select * from " +TableName;
var data=ctx.tbl_Loc1.SqlQuery(query);
}
}
DBEntities is Database Connection String
In ctx.tbl_Loc1.SqlQuery(query);.............. tbl_loc1 has a class in model which will help in getting data in the same format[As all tables have the same table definition]
There is a model of tbl_Loc1 in EF whereas tbl_Loc2 and tbl_Loc3 are only in Database.
Return this data as IEnumerable list
http://www.entityframeworktutorial.net/Querying-with-EDM.aspx
I echo other commenter's thoughts that you probably can handle this all in one table with a distinguishing column (and some proper indexes on the table). What you've mentioned so far only amounts to hundreds of thousands of records, something that should still perform very well.
However, in order to do what you want the way you state it, you can use reflection to examine the properties of your db object. Any property in there that is a hashset is a property that represents a table, so you can get a list of all the hashset properties, and their names (perhaps with a few tweaks regarding pluralization), which will give you your table names.
For a more sophisticated use of metadata within EF, take a look at How I can read EF DbContext metadata programmatically?.
Also, you may find that SMO is a helpful approach to this kind of thing (nothing preventing you from using it and EF).

Entity Framework ensure objects get inserted in order

I have a table Rules on my database. I insert rules like:
Rule[] rulesToInsert = // some array of rules to insert
using(var db = new MyEntities())
{
foreach(var rule in rulesToInsert)
db.Rules.Add(rule);
db.SaveChanges();
}
When I retrieve later the rules that I have just added I notice they are in a different order. What is the best way to retrieve them in the order I added them? Should I call db.SaveChanges() every time I add a new rule? Or should I add a new column called SortOrder? Why are the items not being added in the order I added them?
Edit
The id is a guid (string) because one rule can have other rules. In other words I am creating a tree structure. (The rules table has a foreign key to itself). It was crashing when I used the primary key as an integer and it autoincremented so I just used a guid instead. I guess I will add a separate column called sort order.
Tables have no sort order (new rows are not guaranteed to be added to the end or any other place). The only safe way to retrieve rows in any particular order is to have a query with Order by.
So yes you will need to add a SortOrder column. (Can just set it as an identity column.)
If you want your items to be inserted in the order you add them in the foreach statement, you have to make a big compromise, to call the db.SaveChanges in each iteration.
foreach(var rule in rulesToInsert)
{
db.Rules.Add(rule);
db.SaveChanges();
}
I say that's a big compromise, because for each rule you have to insert you have to make a round-trip to the database, instead of doing only one round-trip as in your original code.
One possible workaround, it would be to add an extra column in the corresponding table in your database, that would hold the information of order. If you do so, you could add one more property in the rule object and refactor a bit your code. Then you will have the expected result.

Entity Framework / Database - Archiving Foreign Key Records

I've developed an application for a client with the following relationship:
A SalesOrder has a foreign key relationship to a Customer (one-to-one).
The client now wants to be able to delete Customers so that they won't be available for any future (new) SalesOrders, but obviously I would like to retain the historical records for reporting, etc. Likewise, the record may need to be update-able in the future in rare cases, so in "Edit" mode the customer would need to be there (but ALL other deleted Customers would not)
I am looking for input on a pattern to model this, or better recommendations. My thought was to have an "Archived" bit on the Customer, but my problem is that if someone loads up an old SalesOrder I would also need to load that archived record for the DropDownList that Customers populate.
Since I'm using Entity Framework and an EntityDataSource, my guess is that I might get a runtime exception on the SelectedValue bind of the DropDownList also, but I haven't verified this.
Any thoughts or recommendations on where to start?
Thank you.
I believe I have a solution. I've been racking my brain on it all day but I think it's fairly easy. In a quick prototype it appears to do what I need it to:
I added an "Archived" bit to the Customers table (actually to the BusinessEntity table they inherit from). Then for the "Edit Sales Order" page, when querying Customers, I have a where clause which includes the customer by ID.
For example (pseudocode):
SELECT CustomerID, Name FROM Customers WHERE Archived = 0 OR CustomerID = 52
That pulls all the active customers and the one customer for the record that I need. This allows the customer to still be linked to the record for editing AND doesn't generate a runtime exception with the DropDownList binding.
For reporting, I assume I'll just not filter based on the Archived bit since it's all read-only anyway.

Linq to SQL SubmitChanges only for specific table

I have been using linq to sql for a little while and often come up against this type of problem....
e.g
I have 2 db tables
-Table: Invoice ("Id" int auto-increment, "InvoiceDate" datetime)
-Table: InvoiceItems ("Id" int auto-increment, "InvoiceId" int (FK), "SomeReference" varchar(50))
The "SomeReference" field holds a value that is a combination of the Id from the parent Invoice record and some random characters. eg. "145AHTL"
Before i can set the value of SomeReference I need to know the value of the Invoice Id, but this only gets populated when it is saved to the DB. I have both parent and child records in the same Linq to SQl DB Context but I only want to perform "SubmitChanges" to the parent Invoice record only, so that i can then populate the SomeReference in the child record. I dont want to have the child InvoiceItem record saved to the DB before SomeReference is set.
How can I achieve this using Linq to Sql?
I understand that linq to sql uses the "Unit of Work" idea for saving to db, but I dont understand how I can avoid unnecessarily saving records to the db when they are not ready to be saved just yet. If there is no way around this, then why do developers bother with linq to sql, as this seems like such a huge drawback?
edit: should note that this example is just something i came up with to help describe my problem.
You can not. Not this way. And this is the only way (linq dues not support sequences). Brutally speaking - you have to fix your logic. The Id of an invoice is not a refernce field. It should not ever never be the number. This is a logical field and should be handled by your logic, outside the Id.
You example can be done, but you need to forget about the SQL and the database, but think in an ORM way.
Two issues need to be addressed in your example
First inserting the master and detail at the same time
Pseudo code for how it works:
using (var dc = new datacontext())
var master = new masterentity;
master.somedata = "data";
dc.tb_master.InsertOnSumbut(master)
var detail = new detailentity
detail.tb_master = master
dc.tb_detail.InsertOnSubmit(detail)
Submitchanges()
So you assign the entities to eachother, not the keys.
Second: the SomeReference
This first part however, does not give you the somereference field, only sets the the foreign key properly.
Your somereference field contains redundant data (not necessary) so that needs to be solved.
The somereference is a string + the ID.
So you store the string part in a column in the database (and only that) and you implement a custom property somereference by using a partial class.
public partial class tb_detail
{
public string somereference
{
get
{
return _id.ToString() + _somestring;
}}}

Committing changes to the database using Entity Framework

I have a situation where I pull data from a table by date. If no data is supplied for a given date I create a record using default values and display it all to the user. When the user is done manipulating the data I need to commit the changes.
So my question is how do I handle in Entity Framework submitting a table where there could be both updates and adds that need to be done. This is in C# using MVC3 and Entity Framework.
So here's what the data might look like to start,
Table A
NAME AGE PHONE_NUM
Jim 25 555-555-5555
Jill 48 555-551-5555
After the users done with the data it could look like this,
Table A
NAME AGE PHONE_NUM
Jim 25 555-555-5555
Jill 28 555-551-5555
Rob 42 555-534-6677
How do I commit these changes? My problem is there are both updates and inserts needed?
I've found some code like this but I don't know if it will work in this case.
For adding rows of data
entities.TABlEA.AddObject(TableOBJECT);
entities.SaveChanges();
or for updating data
entities.TABLEA.Attach(entities.TABLEA.Single(t => t.NAME == TableOBJECT.NAME));
entities.TABLEA.ApplyCurrentValues(TableOBJECT);
entities.SaveChanges();
Will any of this work or do I need to keep track of whats there and what was added?
Ideas?
More or less you already have the solution. You just need to check if your Single call which tries to load the object from the DB has an result or not (use SingleOrDefault instead). If the result is null you need to insert, otherwise update:
foreach (var TableOBJECT in collectionOfYourTableOBJECTsTheUserWorkedWith)
{
var objectInDB = entities.TABLEA
.SingleOrDefault(t => t.NAME == TableOBJECT.NAME);
if (objectInDB != null) // UPDATE
entities.TABLEA.ApplyCurrentValues(TableOBJECT);
else // INSERT
entities.TABLEA.AddObject(TableOBJECT);
}
entities.SaveChanges();
(I'm assuming that NAME is the primary key property of your TableOBJECT entity.)
I think you have to keep track of what is new and what is modified. If you do that, that the two code examples you provided are going to work.
A simple workaround which I used is to check if an entity's primary key property is set to anything. If it is set to a value, then that is an updated object, otherwise it's new.
Another solution would be to use Entity Framework's Self Tracking Entities, but I do not think that's the right direction to go in a web application (maybe it is in a distributed WCF app).

Categories

Resources