Set a custom identity value on a auto increment field - sql-server

I have in my DB (Sql server 2008) a id column with auto numeric set on.
I'm using EF and linq2entities
In some specific scenario I would like to be able to set a custom Id number (obviously I'm totally sure this value is not repeated), for example I would use it to "fill" missing Id numbers caused by deletions. I want to keep the auto increment prop in database, the problem is that when I do the linq sentence, the database assign the next Id number, not the one that I like.
Maybe it's a little weird but is it possible to do using linq2entities ?
Thanks in advance!

I believe Its not possible unless there is some way to turn off "SET Identity_Insert TableName ON" within Entity Framework.
Basically in SQL Server when you sent Identity on a field it cannot be populated manually unless you run the following statement
SET Identity_Insert TableName ON
After running this statement you will be able to populate Identity Fields manually.
The only other options I can think of is to remove the Identity attribute from the column and create your own incrementer for the field in the Entity Framework using a partial Class
Something like this
public partial class EntityClassName : global::System.Data.Objects.DataClasses.EntityObject, IEntity
{
partial void InitializeFields();
Int64 IEntity.IdentityColumn
{
get { return IdentityColumn; }
set { //some code for an incrementer
//and the ability to set manually
//if value provide is not null
}
}
}

I don't like to say flat-out that it's impossible, but this is pretty inside baseball for L2E. But it's a pretty simple INSERT trigger. You'll get the inserted row via INSERTED (Google will explain), and then you update that row with whatever crazy logic you want.
I think you can bang your head against L2E for hours trying to figure it out, or do it inside of twenty minutes with a trigger.

Related

Trigger to restrict duplicate record for a particular type

I have a custom object consent and preferences which is child to account.
Requirement is to restrict duplicate record based on channel field.
foe example if i have created a consent of channel email it should throw error when i try to create second record with same email as channel.
The below is the code i have written,but it is letting me create only one record .for the second record irrespective of the channel its throwing me the error:
Trigger code:
set<string> newChannelSet = new set<string>();
set<string> dbChannelSet = new set<string>();
for(PE_ConsentPreferences__c newCon : trigger.new){
newChannelSet.add(newCon.PE_Channel__c);
}
for(PE_ConsentPreferences__c dbcon : [select id, PE_Channel__c from PE_ConsentPreferences__c where PE_Channel__c IN: newChannelSet]){
dbChannelSet.add(dbcon.PE_Channel__c);
}
for(PE_ConsentPreferences__c newConsent : trigger.new){
if(dbChannelSet.contains(newConsent.PE_Channel__c))
newConsent.addError('You are inserting Duplicate record');
}
Your trigger blocks you because you didn't filter by Account in the query. So it'll let you add 1 record of each channel type and that's all.
I recommend not doing it with code. It is going to get crazier than you think really fast.
You need to stop inserts. To do that you need to compare against values already in the database (fine) but also you should protect against mass loading with Data Loader for example. So you need to compare against other records in trigger.new. You can kind of simplify it if you move logic from before insert to after insert, you can then query everything from DB... But it's weak, it's a validation that should prevent save, it logically belongs in before. It'll waste account id, maybe some autonumbers... Not elegant.
On update you should handle update of Channel but also of Account Id (reparenting to another record!). Otherwise I'll create consent with acc1 and move it to acc2.
What about undelete scenario? I create 1 consent, delete it, create identical one and restore 1st one from Recycle Bin. If you didn't cover after undelete - boom, headshot.
Instead go with pure config route (or simple trigger), let the database handle that for you.
Make a helper text field, mark it unique.
Write a workflow / process builder / simple trigger (before insert, before update) that writes to this field combination of Account__c + ' ' + PE_Channel__c. Condition could be ISNEW() || ISCHANGED(Account__c) || ISCHANGED(PE_Channel__c)
Optionally prepare data fix to update existing records.
Job done, you can't break it now. And if you ever need to allow more combinations (3rd field) it's easy for admin to extend it. As long as you keep under 255 chars total.
Or (even better) there are duplicate matching rules ;) give them a go before you do anything custom? Maybe check https://trailhead.salesforce.com/en/content/learn/modules/sales_admin_duplicate_management out.

How to set value in a field by UI?

I use three fields in Sqlserver Datavbase tables, for prevent delete records permanently by user:
IsDelete (bit)
DeletedDate (DateTime)
DeletedUserID (bigint)
I wish to set third field (DeletedUserID) by UI by some thing like this:
this.ExamdbDataSet.AcceptChanges();
DataRowView row = (DataRowView)this.BindingSource.Current;
row.BeginEdit();
row["DeletedUserID"] = User.User.Current.ID;
row.EndEdit();
this.ExamdbDataSet.AcceptChanges();
row.Delete();
and other two fields ,'IsDeleted' field and 'DeletedDate' are set automatically in table's 'After Delete Trigger'.
then commit changes to database with desire command successfuly with this code:
this.TableAdapterManager.UpdateAll(this.ExamdbDataSet);
but problem is , the 'DeletedUserID' is null in database.
and Question is : How to set 'DeletedUserID' field value by true way in UI?
I don't think it is a good way to do that. You have sliced a simple logic to separate parts, each being done in a different part of the application (UI, Trigger, ...). You set value of some field, and then DELETE the whole record! Don't expect anything else that the current situation.
You would better set all fields in UI (i.e. no trigger in this case), and change the query that loads data. For example,
Select * from table1 where IsDeleted=0
You didn't tell us anything about whether your use ASP.Net or WinForms. Give us more info.

Salesforce Junction Objects

To all salesforce experts i need some assistance. I have my contacts and a custom object named programs. I created a junction object using to master detail relationships with contacts and programs. I want to avoid relating the same contact to the same program. I tried triggers but I couldn't create the testing part to use it outside sandbox.
I went back to the basics and created a Unique text field. I tried to use default value but EVERYTHING i write in that crap is wrong -_-. I tried Contact__r.Email & "-" & Program__r.Name but to no avail.
I tried workflow rules with a field update but my field update NEVER runs.(Yes I did activate the workflow rule) and I didn't know what to write in my rule's code.
The workflow firing condition could be simply a formula that says true. Alternatively use "every time record is inserted". It also depends whether your master-details are set once and that's it or they will be "reparentable" (option introduced in Summer '12 I think). Maybe post a screenshot / text description of your firing condition? Also - is your unique field set to "case sensitive"?
As for the formula to populate the unique field - something like Contact__c + ' ' + Program__c (or whatever the API names of your fields are) should be OK. Don't use Contact__r.Email etc as these don't have to be unique...
You'll have to somehow fill in the uniqueness criteria for all existing records (maybe that's why you claimed it doesn't work?). If you can use Apex for data fixes - something like this should get you started.
List<Junction__c> junctions = [SELECT Contact__c, Program__c
FROM Junction__c
WHERE Unique_Text_Field__c = null
LIMIT 10000];
for(Junction__c j : junctions){
String key = String.valueOf(j.Contact__c).left(15) + ' ' + String.valueOf(j.Program__c).left(15);
j.Unique_Text_Field__c = key;
}
update junctions;
Keep rerunning it until it starts to show 0 rows processed. The Ids are cut down to 15 chars because in Apex you'd usually see full 18-char Id but workflows use 15-char versions.

Is there any way to do a Insert or Update / Merge / Upsert in LLBLGen

I'd like to do an upmerge using LLBLGen without first fetching then saving the entity.
I already found the possibility to update without fetching the entity first, but then I have to know it is already there.
Updating entries would be about as often as inserting a new entry.
Is there a possibility to do this in one step?
Would it make sense to do it in one step?
Facts:
LLBLgen Pro 2.6
SQL Server 2008 R2
.NET 3.5 SP1
I know I'm a little late for this, but As I remember working with LLBLGenPro, it is totally possible and one of its beauties is everithing is possible!
I don't have my samples, but I'm pretty sure you there is a method named UpdateEntitiesDirectly that can be used like this:
// suppose we have Product and Order Entities
using (var daa = new DataAccessAdapter())
{
int numberOfUpdatedEntities =
daa.UpdateEntitiesDirectly(OrderFields.ProductId == 23 && OrderFields.Date > DateTime.Now.AddDays(-2));
}
When using LLBLGenPro we were able to do pretty everything that is possible with an ORM framework, it's just great!
It also has a method to do a batch delete called DeleteEntitiesDirectly that may be usefull in scenarios that you need to delete an etity and replace it with another one.
Hope this is helpful.
I think you can achieve what you're looking for by using EntityCollection. First fetch the entities you want to update by FetchEntityCollection method of DataAccessAdapter then, change anything you want in that collection, insert new entities to it and save it using DataAccessAdapter, SaveCollection method. this way existing entities would be updated and new ones would be inserted to the Database. For example in a product order senario in which you want to manipulate orders of a specified product then you can use something like this:
int productId = 23;
var orders = new EntityCollection<OrderEntity>();
using (DataAccessAdapter daa = new DataAccessAdapter())
{
daa.FetchEntityCollection(orders, new RelationPredicateBucket(OrderFields.ProductId == productId))
foreach(var order in orders)
{
order.State = 1;
}
OrderEntity newOrder = new OrderEntity();
newOrder.ProductId == productId;
newOrder.State = 0;
orders.Add(newOrder);
daa.SaveEntityCollection(orders);
}
As far as I know, this is not possible, and could not be possible.
If you were to just call adapter.Save(entity) on an entity that was not fetched, the framework would assume it was new. If you think about it, how could the framework know whether to emit an UPDATE or an INSERT statement? No matter what, something somewhere would have to query the database to see if the row exists.
It would not be too difficult to create something that did this more or less automatically for single entity (non-recursive) saves. The steps would be something like:
Create a new entity and set it's fields.
Attempt to fetch an entity of the same type using the PK or a unique constraint (there are other options as well, but none as uniform)
If the fetch fails, just save the new entity (INSERT)
If the fetch succeeds, map the fields of the created entity to the fields of the fetched entity.
Save the fetched entity (UPDATE).

How to solve "Batch update returned unexpected row count from update; actual row count: 0; expected: 1" problem?

Getting this every time I attempt to CREATE a particular entity ... just want to know how I should go about figuring out the cause.
I'm using Fluent NHibernate auto-mapping so perhaps I haven't set a convention appropriately and/or need to override somethings in one or more mapping files. I've gone thru a number of posts on the web regarding this problem and having a hard time figuring out exactly why it is happening in my case.
The object I'm saving is pretty simple. It is a "Person" object that references a "Company" entity and has a collection of "Address" entities. UPDATES work fine on existing Person objects that are already in the database.
Any suggestions?
The error means that the SQL INSERT statement is being executed, but the ROWCOUNT being returned by SQL Server after it runs is 0, not 1 as expected.
There are several causes, from incorrect mappings, to UPDATE/INSERT triggers that have rowcount turned off.
Your best beat is to profile the SQL statements and see what happens. To do that either turn on nHibernate sql logging, or use the sql profiler. Once you have the SQL you may know the cause, if not try running the SQL manually and see what happens.
Also I suggest you to post your mapping, as it will help people spot any issues.
This can happen when trigger(s) execute additional DML (data modification) queries which affect the row counts. My solution was to add the following at the top of my trigger:
SET NOCOUNT ON;
This may occur because of Auto increment primary key. To solve this problem do not inset auto increment value with data set. Insert data without the primary key.
When targeting a view with an INSTEAD OF trigger it can be next to impossible to get the correct row count. After delving a bit into the source I found out that you can make a custom persister which makes NHibernate ignore the count checks.
public class SingleTableNoResultCheckEntityPersister : SingleTableEntityPersister
{
public SingleTableNoResultCheckEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory, IMapping mapping)
: base(persistentClass, cache, factory, mapping)
{
for (int i = 0; i < this.insertResultCheckStyles.Length; i++)
{
this.insertResultCheckStyles[i] = ExecuteUpdateResultCheckStyle.None;
}
for (int i = 0; i < this.updateResultCheckStyles.Length; i++)
{
this.updateResultCheckStyles[i] = ExecuteUpdateResultCheckStyle.None;
}
for (int i = 0; i < this.deleteResultCheckStyles.Length; i++)
{
this.deleteResultCheckStyles[i] = ExecuteUpdateResultCheckStyle.None;
}
}
}
if you get row count greater than 1 its usually because you have duplicate rows in a table that have same ids. Check your table for duplicated records. Deleting duplicates will fix it.
NHibernate.AdoNet.TooManyRowsAffectedException: 'Batch update returned
unexpected row count from update; actual row count: 2; expected: 1'

Resources