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;
}}}
Related
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).
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.
Suppose we have a database with two tables Product and ProductField. Table ProductField contains several fields related to each Product in the Product table. So For one product it's Id repeats several times in ProductField. That's a nice schema for saving customized products with several different fields for each one.
But there is a problem with this naive solution. For example in the above image you can see that product fields have different types, string for Name and numerical value for Price field. Therefore we have to save the type of each field, somewhere in our application. I thought it would be good idea to save this types in another table as follows:
This solves the problem of unknown types. But there still exist type casting problem. Because we still need to save all values in the field value of the first table which is a string column. So we have to cast the values to the required type in our application. This is the code we need:
// string fieldType retrieved from database
// string fieldValue retrieved from database
if (fieldType == "string")
{
// do something with fieldValue
}
else if (fieldType == "int")
{
// do something with int.Parse(fieldValue)
}
.
.
The third solution is to use one table for each field type. The following picture illustrates the solution I have in my mind.
As you can see one disadvantage of this solution is that you can not create new field types straightforward. You have to create new tables and change database schema in run time if you want to add new field types.
But one advantage of this solution is that you do not need to cast the string value to int or double or whatever the real format of the saved value is.
What do you think about the third solution? Does it make sense?
Assuming you really really need to have one table that caters for different product types with different characteristics, a simple way to go would be to have 3 tables:
header table that includes all products (product id is a primary key)
table for quantifiable fields (floats) with N rows per product (price, size, percentile, ...)
table for un-quantifiable fields (varchar) with N rows per product (description, warnings, ...)
something like this:
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.
I have a table with a varbinary(max) column for an image. I have dropped the table on the LinqToSql designer and have set "Delay load" to true, since I don't want to load the actual image data.
Is it possible to just know if the column is null or not, without getting the actual data and still only doing one query from the database?
I would also like to use the automated entity created by Linq.
Something like a new bool HasImage {get;} property would be just what I'm looking for.
The only way for Linq to SQL to "automatically" know whether or not the column has a value is to actually ask the database for it. You can extend the partial class with fields/properties, but that's not going to eliminate the lookup.
One of the things you could do is created a computed column (assuming SQL 2005+ here, otherwise you'll have to try to adapt this to your DBMS). If your table looks like this, for example:
CREATE TABLE Foo
(
FooID int NOT NULL IDENTITY(1, 1) PRIMARY KEY,
FooName varchar(50) NOT NULL,
FooImage varbinary(max) NULL
)
You would add the computed column this way:
ALTER TABLE Foo
ADD FooHasImage AS CASE
WHEN FooImage IS NULL THEN 0
ELSE 1
END
Then you can add the FooHasImage column to your Linq to SQL entity, don't delay load it, and check that property instead of explicitly checking the FooImage property.
Also, I feel obligated to point out that storing images in a database this way is sub-optimal. It may be necessary, I don't know much about your environment, but if you're using SQL Server 2008 then consider using FILESTREAM instead, as it will use the file system for cheap "offline" BLOB storage instead of stuffing the entire thing in the database.
Create a partial class
public partial class MyTableObject
{
public bool HasImage { get { return MyColumn.HasValue; } }
}
this will probably trigger a database hit, though
I would suggest adding a new column to the database "HasImage" bit that you set when an image is uploaded or deleted
don't know the actual answer to your Q, but in case you don't get an answer: how about doing the change yourself in the DB. (that is of course if you have control over the DB design).
and put the HasImage (or HasContent) column straight in the table, with a default "false" and when you add the image you make it "true" and than you can consult that column to see if you have an image or not.