Letting the database pick the primary key in nhibernate - c#

How do I just simply allow MySQL to assign a primary key to an inserted object with nhibernate? It seems I would want to set the generator as a type "identity", but the documentation states that using this "..require[s] two SQL queries to insert a new object." Why would it do that? Is there some way to get this functioning like a normal insert sql statement?

The reason that it requires two queries is that with an identity the value of the column is not defined until the row is inserted. Therefore it requires a select after insert to get the column value for the inserted object. This is pretty standard and I wouldn't let it stop me from using autogenerated keys as my primary key. The other option is to pre-generate the key -- say a GUID for the new object before persisting it to the database. For the most part I don't really see an advantage to this unless there are other mitigating circumstances, such as having to merge data from separate databases where autogenerated keys might collide.

There's an obvious advantage: Letting NHibernate use Guids or Hilo as the id generator will enable an extremely cool feature in NHibernate: batching. Just configure NHibernate to use batching (for like, say 1000 statements), and your inserts will suddenly be extremely fast.
Fabio has a post about the various availabe generators here - extremely useful reading if you are using NHibernate (or if you know someone who thinks NHibernate performs badly).

Related

What is best practice for checking for an existing record with a primary key while using Entity Framework?

What is the best practice to handle the following situation?
It is known that many records (thousands) will be inserted with a fair possibility of a primary key exception. In some cases the exception should trigger some alternative queries and logic. In other cases it doesn't matter much and I merely want to log the event.
Should the insert be attempted and the exception caught?
or
Should a query be made to check for the existing record, then attempt the insert if none exists?
or Both?
I have noticed slightly better performance when merely catching the exception, but there's not a significant difference.
IMO It depends. If the client is responsible for generating a PK, using a UUID or Snowflake etc. where keys are expected to be unique then the first option is fine. Whether you bother with a retry after generating a new ID or simply fail the operation and ask the user to try again (as it should be a 1 in a billion exception, not the norm) is up to you. If the data is relying on sequences or user-entered meaningful keys it should be managed at the DB side using DatabaseGenerated.Identity and meaningless keys with related object graphs created and committed within a single SaveChanges call.
The typical concern around ID generation and EF is usually where developers don't rely on EF/the DB to manage the PK and FKs through navigation properties. They feel they need to know the PK in order to set FKs for related data, either saving the primary entity to get the PK or generating keys client-side. One of the key benefits of using an ORM like EF is giving it the related objects and letting it manage the inserting of PKs and FKs automatically.
There are couple of things over here.
One thing required is that you must have primary key vonstraint on column at the database Level
Now at the Entity Framework level, it is good if you check whether the record exists or not. So basically what happen you query for record using primary key and if it is found, then it return the entity and then you make changes to entity and at last SaveChanges will save that entity
Now if you are not able to find entity then you have to add entity
If you try without query then it is problematic for EF and specially if multiple request try to update same record
Now one more case is that, lets assume that there is possibility that multiple request can insert same record and so primary key constraint will help here and it will not allow duplication if you are generating primary key manually
For update too, there is possibility of data loss if you are not taking care of concurrency

Is it OK to generate IDs of entities outside of CRM?

I need to one-way-synchronize external Data with CRM on a regular basis (i.e. nightly).
This includes creating new Records as well as updating existing ones.
That means, I have to keep track of IDs of CRM-Entities created by my synchronization process.
emphasized textI already managed to create and update records in CRM from lines of database-tables so this is not a problem.
Currently, my mapped tables have the following columns
id: The tables primary key set when inserting a new row
new_myentityid: Primary Attribute of the mapped entity, set after the record was created by the synchronization process
new_name etc.: the values of the records attributes
However, I see a way to drastically simplify the whole process:
Instead of having a PrimaryKey (id) in the database and keeping track of the CRM ID (new_myentityid) in a seperate column, I could as well get rid of the id-columns and make the CRM-ID-Column (new_myentityid) primary key of the table and set it when inserting new records (newid()), so basically substitute id with new_myentityid from a database perspective. I could then bulk-upsert via ExecuteMultipleRequest in combination with UpsertRequest.
This way, I would save a column in each mapped table as well as logic to store the CRM IDs after creating them.
Question
Would this be acceptable or is there anything that should make me avoid this?
Disclaimer: I'm not aware of a best practice for this so this is just my personal opinion on the matter having developed for Dynamics several times.
I think that using the CRM Entity GUID for your primary key is a good idea. It's less complicated and is handled well in SQL. I assume the column in your database is uniqueidentifier.
My only comment is to not generate the GUIDs yourself. Let CRM generate them for you as it does a better job at keeping everything sequential and indexed.
See this blog entry on MSDN for further detail
I'm probably a little late to this discussion but just wanted to add my tuppence worth.
There is nothing inherently wrong with specifying the GUID when creating a new record in CRM, and this behaviour is explicitly supported by the SDK.
A common real life scenario is when creating records by script; it is useful to have the same GUID for an entity in Dev, Test and Production environments (Admittedly we normally use the GUID auto generated in Dev).
The reason that it is considered best practice to allow CRM generate its own GUID (https://msdn.microsoft.com/en-us/library/gg509027.aspx) is that CRM will generate the GUID sequentially. Using newid() generates a statistically random GUID. This has a performance impact on SQL server around index maintenance. This thread provides some insight: What are the performance improvement of Sequential Guid over standard Guid?
But basically specifying your own GUID can cause the underlying SQL INSERT statement to become more expensive. Read and Update operations should remain the same.
If you are generating you own GUIDs is SQL you can always use NEWSEQUENTIALID (https://msdn.microsoft.com/en-us/library/ms189786.aspx) for a sequentially generated GUIDs.
Hi previous posts cover this well. Just to note that if you did go with generating GUIDs outside of CRM you could mitigate against the potential performance impact (INSERTS) simply by running a weekly Maintenance plan to refresh the clustered indices directly on the SQL database(s) this would I believe ensure that GUIDs were ordered sequentially. In any case, CRM/API will always be the bottleneck, so best to do things in the way that the platform expects to avoid issues later on.
Why not save in new table?
likes origin exist a table named "customer",and your new data save in "customer_update",the field as same as the origin table.
it's will help you in future.maybe you want have a look the data's orgin.

How to generate a uniqueidentifier in sql if null

I am trying to add a column to an existing SQL table of uniqueidentifier type. That column must not be null and of course unique. I have attempted this code:
ALTER TABLE ScheduleJobs ADD CurrentInstanceID uniqueidentifier not null
followed by:
ALTER TABLE ScheduleJobs ADD CONSTRAINT DF_CurrentInstanceID DEFAULT newsequentialid() FOR CurrentInstanceID
However, when I create a new record (from C#), the uniqueidentifier is always all zeros (presumably null.) I can create the GUID in C# and pass it to sql upon creating a new record which works fine, but I am concerned that a duplicate GUID could be created. Based on my readings, it appears that would be an extremely rare case, but it always seems bad practice to have any sort of potential error floating around. Note that the field will not be a PK for the table. Suggestions and opinions welcome for the sake of education.
I am using C# 4.0 framework with MS SQL SERVER 2008
Sorry for the delay, but I am glad to say that I have this issue resolved. Thanks everyone for your overwhelming support. While no one quite hit the nail on the head (and there were some really good suggestions btw), Eldog brought up Entity Framework not playing nice in his comment. Thanks to him, I simply Googled Entity Framework + GUID and found the solution.
This article steps through the issue and gives a great explanation on the problem, solution, and steps to resolve it. I will note that I decided to step through and test one step at a time and that I didn't have to do the last step. That leads me to believe that part of the issue may have been resolved in later versions of the Entity Framework.
I simply pulled up the edmx file in design view (not xml) and set the StoreGeneratedPattern property to "Identity."
Thanks again for the help and suggestions. You're an awesome bunch.
Does your C# code attempt to pass in a CurrentInstanceID when creating the record? If so, can you drop that column from the INSERT statement?
We do this with numeric primary keys. Our C# code calls a stored procedure for CRUD operations on our records. The C# code generates a negative key on the client side for its own use. When it is ready to create the record, it passes this key to the stored procedure.
The proc ignores this key and inserts the rest of the data. The output of the proc is the actual key that SQL assigned to the record. Finally, the C# code merges the new key into the existing data.
I wouldn't use a GUID for this. GUIDs are used in quite a lot of operations in windows, so this won't be an identifier that will be only unique in your application, it will be a unique identifier in your operating system. Unless this makes sens in your case, I wouldn't use it.
You could use an incremental value, like a simple uint. If your table already has some data, you could write a script that fills existing rows with incremental values for your new column, and add the unique contraint to your column after executing that script.
in your original Create table or alter table use something like the following
create table ScheduleJobs (keyval int, id2 uniqueidentifier not null default newsequentialid())
then don't reference the column in your insert and a new GUID value will be added

Updating primary keys using LINQ

I'm currently working on a sandbox environment based on two databases located on different servers. What I am aiming to do is allow my clients to make changes on a test server and then once approved, I can simply hit a button and import the data across to my live database.
So far, I have managed to port the data across the two databases but what I would like to do is amend the primary keys on the test server to match those held on the live (incase I need backups and so that I can make checks to stop the same information being copied multiple times).
So far I have tried this solution:
DT_SitePage OldPage = new DT_SitePage
{
PageID = SP.PageID
};
DT_SitePage NewPage = new DT_SitePage
{
PageID = int.Parse(ViewState["PrimaryKey"].ToString())
};
Sandbox.DT_SitePages.Attach(NewPage, OldPage);
Sandbox.SubmitChanges();
However I keep getting the error:
***Value of member 'PageID' of an object of type 'DT_SitePage' changed.
A member defining the identity of the object cannot be changed.
Consider adding a new object with new identity and deleting the existing one instead.***
Is there anyway in LINQ to avoid this error and force the database to update this field???
Many Thanks
Why won't you use the stock backup/restore functionality supplied by DB manufacturer?
It makes a perfect logical sense that high-level ORM tools won't allow you to change the primary key of the record, as they only identify the record by its primary key.
You should consider making direct UPDATE queries to DB from your code instead.
And anyway, changing the primary key is the bad idea, what prevents you from INSERTing it with the needed value in the first place?
As said, modifying primary keys is typically something you don't want to do. If Linq-to-sql wouldn't have the early warning, your RDBMS would probably complain (SQL server does!). Especially when records are related by foreign key constraints updating primary keys is not trivial.
In cross-database scenarios, it is more common to use some "global" unique identification, for which GUIDs may do. Maybe your data can be identified in an alternative way? (Like when two users have the same name, they are deemed identical).
If you don't need to keep identical the database structures, you may consider using an extra field in your test database to store the "live" primary key.
Here is a post with lots of useful thoughts.

how to insert data in sql table using Linq without seting any primary key in table

I have a Table in which i don't want to specify any primary key, after that i am inserting records in it using Linq...aahhh...its giving the error
"Can't perform Create, Update or Delete operations on 'Table(abc)' because it has no primary key"
can ani one tell me how to insert record without setting it primary key.
By the way im not setting any primary key because this table will have bulk of data to keep.
You can't use Linq-to-SQL directly with tables that don't have primary keys, because it's not supported.
If you're worried about the performance hit of indexing, what you can do is add a Stored Procedure that does the insert and add that to your data context. It's a bit more work, and it's not really Linq-to-SQL, it'll just be a method on that you call on your data context.
There probably won't be a noticeable performance hit on an identity primary key field anyway.
Tami - would it not be a good idea to stick to 'best practices' when using linq and add a autonumber primary key, even if it isn't going to be used other than for inserts or updates?? i can think of many instances where the seemingly 'non requirement' for a primary key later leads to trouble when trying to update to other platforms etc.
If there's a compelling reason to not add a 'blind' primary key, then it might help to detail this as well in the question. I can't think of any reasons not to add it, especially if it means that you don't have to code around the limitation.
jim
[edit]
Tami - i'll be honest with you. you might have to investigate conventions to best satisfy any answer to this question. basically, altho' you don't 'need' an index on your records, due to not being edited or deleted, the convention with linq is based around the assumption of data integrity. in essence, linq (and many other programatic tools) require a convention that allows them to succinctly identify a unique key on each object that they bring into scope. by not defining this, you are by-passing this convention and therefore linq is flagging this up for you. the only way fwd is to go with the flow. even if you 'feel' that the index is redundant, linq requires it to allow you to access the full functionality built into it.

Categories

Resources