How to prevent duplicate record on run time - c#

This code cause double record...
i checked my insert code for all tables and it works fine...
and this is insert code:
StoreDO store = new StoreDO();
List<BrandDO> brandList = new BrandBL().SelectBrands();
StoreBL storeBL = new StoreBL();
store.StoreName = txtStoreName.Text;
store.StorePhone = txtStorePhone.Text;
store.StoreAddress = txtStoreAddress.Text;
store.CityID = int.Parse(ddlCity.SelectedValue);
store.CountyID = int.Parse(ddlCounty.SelectedValue);
store.IsActive = chkIsActive.Checked;
int storeID = storeBL.InsertStore(store);
ContentPlaceHolder contentPlaceHolder = (ContentPlaceHolder)Master.FindControl("ContentPlaceHolder1");
for (int i = 0; i < brandList.Count; i++) {
string brandName = brandList[i].BrandName.ToString() + brandList[i].BrandID.ToString();
StoreBrandBL storeBrandBL = new StoreBrandBL();
CheckBox chkBrand = (CheckBox)contentPlaceHolder.FindControl(brandName);
if (chkBrand != null) {
if (chkBrand.Checked) {
StoreBrandDO storeBrandDO = new StoreBrandDO();
storeBrandDO.StoreID = storeID;
storeBrandDO.BrandID = brandList[i].BrandID;
storeBrandDO.IsActive = true;
storeBrandBL.InsertStoreBrand(storeBrandDO);
}
}
}

Duplicating rows in your database should be avoided in the code and protected against in the database.
As hwcverwe said you can use table constraints but you should also try to set the primary key correctly for each table.
If you are using surrogate keys on all tables (such as the StoreID and BrandID I see in your code) then you will have to use unique table constraints to prevent duplicate data. Configuring your database correctly will also show up the problem areas in your code as the database will throw an exception when an insert fails.
EDIT: In response to your comment your question title is incorrect if you are asking about CheckBox controls.
Looking at the code it appears you are trying to find a checkbox control in a ContentPlaceholder but you do not show the code which creates the checkboxes.

Related

insert multiple records one by one using LINQ

I'm trying to copy ProductStatisticsTemp table data to ProductStatistics table,
var str = from a in db.ProductStatisticsTemp select a;
ProductStatistics ls = new ProductStatistics();
foreach (var val in str.ToList())
{
ls.Product_ID = val.Product_ID;
ls.ProductNameEn = val.ProductNameEn;
ls.ProductNameAr = val.ProductNameAr;
db.ProductStatistics.Add(ls);
db.SaveChanges();
}
first record can insert but once its try to insert 2nd one getting following error
The property 'Product_ID' is part of the object's key information and
cannot be modified.
It's because you have one instance of an object and try to add already added object twice.
You need to create new object of ProductStatistics in the loop.
Also you can save changes just once after the loop to improve performance by trigger DB communication just once:
var str = from a in db.ProductStatisticsTemp select a;
foreach (var val in str.ToList())
{
ProductStatistics ls = new ProductStatistics
{
Product_ID = val.Product_ID,
ProductNameEn = val.ProductNameEn,
ProductNameAr = val.ProductNameAr
};
db.ProductStatistics.Add(ls);
}
db.SaveChanges();
Here is a slightly different method.
var products = db.ProductStatisticsTemp.Select(t => new ProductStatistics
{
Product_ID = t.Product_ID,
ProductNameEn = t.ProductNameEn,
ProductNameAr = t.ProductNameAr
}).ToList()
db.ProductStatistics.AddRange(products);
db.SaveChanges();
IMHO Inspired from #Vadim Martynov
If the Product_ID is your primary key, and your set to increment
the key from database . Do not do this Product_ID = val.Product_ID.
The key should be generated from the database. You will get the id
after save changes is invoked.
try
{
var str = from a in db.ProductStatisticsTemp select a;
//This will improve some performance
db.Configuration.AutoDetectChangesEnabled = false;
foreach (var val in str.ToList())
{
ProductStatistics ls = new ProductStatistics
{
Product_ID = val.Product_ID,
ProductNameEn = val.ProductNameEn,
ProductNameAr = val.ProductNameAr
};
//use AddRange or Add based on your EF Version.
db.ProductStatistics.Add(ls);
}
db.SaveChanges();
}
finally
{
db.Configuration.AutoDetectChangesEnabled = true;
}
If you are using AddRange you could omit db.Configuration.AutoDetectChangesEnabled = false
For more info about DetectChanges available here
AddRange() method only support from EF6 see documentation
db.ProductStatistics.AddRange(products);
What AddRange will do for you is
if AutoDetectChangesEnabled is set to true (which is the default), then DetectChanges will be called once before adding any entities and will not be called again.
This means that in some situations AddRange may perform significantly
better than calling Add multiple times would do.
Note that entities that are already in the context in some other state will have their state set to Added. AddRange is a no-op for entities that are already in the context in the Added state.

Convert GridView to List<object>

Hi and thanks in advance. I'm having a problem implementing a suggestion that I found here: Convert contents of DataGridView to List in C#
I am grabbing a GridView from a Master page and I need to add a row to the table then rebind it. I am accessing the GridView via a public property on the Master page which is being returned with data. So basically I have done this:
var gsr = master.GridSearchResults;
gsr (gsr != null)
{
var so = new List<MyProperties>();
so = gsr .Rows.OfType<DataGridViewRow>().Select(r => r.Cells.OfType<DataGridViewCell>().Select(c => c.Value).ToArray()).ToList<MyProperties>();
so.Add(new MyProperties()
{
Id = id,
Date = date,
Building = buildingName,
Street = streetName
}
gsr.DataSource = so;
gsr.DataBind();
}
But I'm receiving an error that it cannot convert an instance argument type System.Collections.Generic.IEnumerable<'object[]'> to System.Collections.Generic.IEnumerable<'MyProperties'>. I thought the problem was the call to the array but if I remove it then I just get a variation of the same error.
Turns out my issue was that I shouldn't have been getting the gridview in the first place but getting the the Gridview's source which was in session. So I solved it like this:
var master = (Tab)Master;
master.GridSearchResults.DataSource = null;
var sessions = new Sessions();
sessions.SlideOutSource.Add(new MyProperties {
Id = Id,
StartDate = hidStartDate.Value,
Installation = txtInstall.Text,
Command = txtCommand.Text });
master.GridSearchResults.DataSource = sessions.SlideOutSource;
master.GridSearchResults.DataBind();

Why am I getting index out of bounds error from database

I know what index out of bounds is all about. When I debug I see why as well. basically what is happening is I do a filter on my database to look for records that are potential/pending. I then gather a array of those numbers send them off to another server to check to see if those numbers have been upgraded to a sale. If it has been upgraded to a sale the server responds back with the new Sales Order ID and my old Pending Sales Order ID (SourceID). I then do a for loop on that list to filter it down that specific SourceID and update the SourceID to be the Sales Order ID and change a couple of other values. Problem is is that when I use that filter on the very first one it throws a index out of bounds error. I check the results returned by the filter and it says 0. Which i find kind of strange because I took the sales order number from the list so it should be there. So i dont know what the deal is. Here is the code in question that throws the error. And it doesn't do it all the time. Like I just ran the code this morning and it didn't throw the error. But last night it did before I went home.
filter.RowFilter = string.Format("Stage = '{0}'", Potential.PotentialSale);
if (filter.Count > 0)
{
var Soids = new int[filter.Count];
Console.Write("Searching for Soids - (");
for (int i = 0; i < filter.Count; i++)
{
Console.Write(filter[i][1].ToString() + ",");
Soids[i] = (int)filter[i][1];
}
Console.WriteLine(")");
var pendingRecords = Server.GetSoldRecords(Soids);
var updateRecords = new NameValueCollection();
for (int i = 0; i < pendingRecords.Length; i++)
{
filter.RowFilter = "Soid = " + pendingRecords[i][1];
filter[0].Row["Soid"] = pendingRecords[i][0];
filter[0].Row["SourceId"] = pendingRecords[i][1];
filter[0].Row["Stage"] = Potential.ClosedWon;
var potentialXML = Potential.GetUpdatePotentialXML(filter[0].Row["Soid"].ToString(), filter[0].Row["Stage"].ToString());
updateRecords.Add(filter[0].Row["ZohoID"].ToString(), potentialXML);
}
if i'm counting right line 17 is the error where the error is thrown. pendingRecords is a object[][] array. pendingRecords[i] is the individual records. pendingRecords[i][0] is the new Sales OrderID (SOID) and pendingRecords[i][1] is the old SOID (now the SourceID)
Any help on this one? is it because i'm changing the SOID to the new SOID, and the filter auto updates itself? I just don't know
Well I ended up changing how it worked all together and it actually sorts it a bit nicer now. The code i am about to post has a bunch of hard coded numbers due to the structure of my table that is returned. Sorry about that. I have learned since then to not do that, but i am working on a different project now and will change that when I have to change the program. But here is the solution.
var potentials = Server.GetNewPotentials(); //loads all records from server
for (int i = 0; i < potentials.Length; i++)
{
var filter = AllPotentials.DefaultView;
var result1 = CheckSoidOrSource(potentials[i].Soid, true);
var result2 = CheckSoidOrSource(potentials[i].SourceID,false) ;
//This potential can't be found at all so let's add it to our table
if (result1+result2==0)
{
Logger.WriteLine("Found new record. Adding it to DataTable and sending it to Zoho");
AllPotentials.Add(potentials[i]);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
ZohoPoster posterInsert = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.insertRecords);
AllPotentials.Rows[index]["ZohoID"] = posterInsert.PostNewPotentialRecord(3, filter[0].Row);
}
//This potential is not found, but has a SourceId that matches a Soid of another record.
if (result1==0 && result2 == 1)
{
Logger.WriteLine("Found a record that needs to be updated on Zoho");
ZohoPoster posterUpdate = new ZohoPoster(Zoho.Fields.Potentials, Zoho.Calls.updateRecords);
filter.RowFilter = string.Format("Soid = '{0}'", potentials[i].SourceID);
var index = AllPotentials.Rows.IndexOf(filter[0].Row);
AllPotentials.Rows[index]["Soid"] = potentials[i].Soid;
AllPotentials.Rows[index]["SourceId"] = potentials[i].SourceID;
AllPotentials.Rows[index]["PotentialStage"] = potentials[i].PotentialStage;
AllPotentials.Rows[index]["UpdateRecord"] = true;
AllPotentials.Rows[index]["Amount"] = potentials[i].Amount;
AllPotentials.Rows[index]["ZohoID"] = posterUpdate.UpdatePotentialRecord(3, filter[0].Row);
}
}
AllPotentials.AcceptChanges();
}
private int CheckSoidOrSource(string Soid, bool checkSource)
{
var filter = AllPotentials.DefaultView;
if (checkSource)
filter.RowFilter = string.Format("Soid = '{0}' OR SourceId = '{1}'",Soid, Soid);
else
filter.RowFilter = string.Format("Soid = '{0}'", Soid);
return filter.Count;
}
basically what is happening is that i noticed something about my data when I filter it this way. The two results would only return the following results (0,0) (0,1) and (1,0) (0,0) means that the record doesn't exist at all in this table so I need to add it. (1,0) means that the Sales Order ID (Soid) matches another Soid in the table so it already exists. Lastly (0,1) means that the Soid doesn't exist in this table but i found a record that has the Soid as it's source...which to me means that the one that had it as a source has been upgraded from a potential to a sale, which in turn means i have to update the record and Zoho. This worked out to much less work for me because now I don't have to search for won and lost records, i only have to search for lost records. less code same results is always a good thing :)

Entity DB Adding New User and Other Related Data to DB

Hey. Nooby question but new with Entity.
I am trying to create a new user object and some details in some additional tables which have a foreign key of the newly created user id.
I've attempted to do this in one round trip. Do I have to add the user to the database first and then go back, set the userid's on the other objects and add them. Here is the Entity Model and code to elaborate:
using (var context = new ServicesEntities())
{
newUser = new UsersTable();
newUser.Address = user.UserDetails.Address;
newUser.City = user.UserDetails.City;
newUser.Country = user.UserDetails.Country;
newUser.Email = user.Email.EmailString;
newUser.FirstName = user.UserDetails.FirstName;
newUser.LastName = user.UserDetails.LastName;
newUser.State = user.UserDetails.State;
newUser.Zip = user.UserDetails.Zip;
context.UsersTables.AddObject(newUser);
context.SaveChanges();
}
using (var context = new ServicesEntities())
{
var referralDetails = new UserReferrals();
referralDetails.CreatedThruServiceId = 1; // todo don't make this an absolute 1
referralDetails.ReferralEmail = user.ReferralDetails.ReferralEmail;
referralDetails.TwoPlusTwoHandle = user.ReferralDetails.TwoPlusTwoHandle;
referralDetails.UserId = newUser.UserId;
context.UserReferrals.AddObject(referralDetails);
context.SaveChanges(); // THIS WORKS FINE!
}
using (var context = new ServicesEntities())
{
var credentials = new UserCredentials();
credentials.CreatedOn = DateTime.Now;
credentials.EmailValidated = false;
//credentials.EmailValidatedOn = null;
credentials.FailedLoginAttempts = 0;
credentials.IsLockedOut = false;
//credentials.LastValidLogin = null;
credentials.Password = user.Password.PasswordString;
credentials.PermissionId = 1; // todo don't make this an absolute 1 = user
credentials.SuccessfulLoginAttempts = 0;
credentials.UserId = newUser.UserId; ;
context.UserCredentials.AddObject(credentials);
context.SaveChanges(); // THIS ONE CRAPS OUT!
}
When I run this I get the following Exception when I run SaveChanges():
{"A dependent property in a
ReferentialConstraint is mapped to a
store-generated column. Column:
'UserId'."}
Note: Updated this with some slightly different code based on an example in a book.
Note2: I've narrowed down the problem to be in the adding of credentials.
Note3: Fixed this, I accidentally had AUTO-INCREMENT set on my UserCredentials userid. If anyone ares here is working code:
public POCO.User AddNewUserToDb(User user)
{
if (IsDuplicateUser(user.Email.EmailString))
{
throw new DuplicateNameException("This email is already taken.");
}
UsersTable newUser;
using (var context = new ServicesEntities())
{
newUser = new UsersTable();
newUser.Address = user.UserDetails.Address;
newUser.City = user.UserDetails.City;
newUser.Country = user.UserDetails.Country;
newUser.Email = user.Email.EmailString;
newUser.FirstName = user.UserDetails.FirstName;
newUser.LastName = user.UserDetails.LastName;
newUser.State = user.UserDetails.State;
newUser.Zip = user.UserDetails.Zip;
var referralDetails = new UserReferrals();
referralDetails.CreatedThruServiceId = 1; // todo don't make this an absolute 1
referralDetails.ReferralEmail = user.ReferralDetails.ReferralEmail;
referralDetails.TwoPlusTwoHandle = user.ReferralDetails.TwoPlusTwoHandle;
//referralDetails.UserId = newUser.UserId;
var credentials = new UserCredentials();
credentials.CreatedOn = DateTime.Now;
credentials.EmailValidated = false;
//credentials.EmailValidatedOn = null;
credentials.FailedLoginAttempts = 0;
credentials.IsLockedOut = false;
//credentials.LastValidLogin = null;
credentials.Password = user.Password.PasswordString;
credentials.PermissionId = 1; // todo don't make this an absolute 1 = user
credentials.SuccessfulLoginAttempts = 0;
//credentials.UserId = newUser.UserId; ;
newUser.Credentials = credentials;
newUser.ReferralDetails = referralDetails;
context.UsersTables.AddObject(newUser);
context.SaveChanges();
}
user.UserId = newUser.UserId;
return user;
Try to add related records directly to UserTable record:
newUser.Credentials.Add(credentials);
newUser.ReferralDetails.Add(referralDetails);
Do not set any Id. It will be set during saving automatically.
Edit: Btw. make sure that UserId column in UserCredentials table is not set as auto generated in database.
Take a look at these links:
Using the entity framework to add existing entities to a collection on a newly created entity.
How to create foreign key relationships with the Entity Framework?
Entity Framework - insert new object with a collection of existing objects
The key links for EF4:
Fortunately, in EF4 we can directly
update the relationship due to the
Foreign Key Association which allows
us to keep the foreign key property
inside the entity classes. For
detail, please see
http://blogs.msdn.com/adonet/archive/2009/11/06/foreign-key-relationships-in-the-entity-framework.aspx.
Besides, we have another great feature
Self Tracing Entities, which makes the
n-tier pattern much easier in EF,
http://blogs.msdn.com/adonet/archive/2009/11/15/updated-feature-ctp-walkthrough-self-tracking-entities-for-the-entity-framework.aspx.
EF4 will allow you to include the foreign key values as scalar properties of your entities. Make sure the "Include foreign keys" checkbox is checked when you create your EDM.
Looking at your model, it looks like you've already done that. Just set the foreign key values explicitly, no need to do a round trip.

Do I need to call InsertOnSubmit for every row that references a main row?

LINQ to SQL - When inserting a row (and several other rows with FKs that will point to the PK on this row), is it sufficient to execute [context].[MainTable].InsertOnSubmit(row), or do I need to call it for the other rows as well?
Here's a condensed code sample (C#):
//Forgive the contrived example (off the top of my head) :)
//Main row
Order order = new Order
{
itemId = (int) data["itemNumber"],
address = (string) data["address"]
};
db.Orders.InsertOnSubmit(order); //would be nice to only have to submit here.
//Related rows
OrderPerson orderPerson = new OrderPerson
{
Order = order,
//other things, etc.
orderRoleId = RoleIds.Customer
};
//Q: need to do "db.OrderPerson.InsertOnSubmit(orderPerson);" here?
OrderHistoryEntry historyEntry = new OrderHistoryEntry
{
Order = order,
//other things, etc.
historyTypeId = HistoryIds.Ordered
};
//Q: need to do "db.OrderHistoryEntry.InsertOnSubmit(historyEntry);" here?
db.SubmitChanges();
Is it sufficient to do: db.Orders.InsertOnSubmit(order); or do I need to also execute InsertOnSubmit for the related rows (orderPerson and historyEntry)?
It would be nice to only run it once on the main row. The MSDN examples do just that, but they all have the relationships reversed (referencing the other rows from main row).
I appreciate your thoughts.
How about this instead?
Order order = new Order
{
itemId = (int) data["itemNumber"],
address = (string) data["address"]
};
OrderPerson orderPerson = new OrderPerson
{
orderRoleId = RoleIds.Customer
};
order.OrderPersons.Add(orderPerson);
OrderHistoryEntry historyEntry = new OrderHistoryEntry
{
historyTypeId = HistoryIds.Ordered
};
order.OrderHistoryEntries.Add(historyEntry);
db.Orders.InsertOnSubmit(order);
db.SubmitChanges();

Categories

Resources