db.SaveChanges() Exploding with Transaction Exception - c#

The following method is causing the FIRST db.SaveChanges() to throw an exception:
(New transaction is not allowed because there are other threads running in the session.)
protected void btnInsertDependencies_Click(object sender, EventArgs e)
{
using (icmsEntities db = new icmsEntities())
{
var divisions = db.Divisions;
foreach (var division in divisions)
{
var dlc_sectors = db.Sectors.Where(s => s.Website.division_id == division.division_id).DistinctBy(s => s.name).ToList();
foreach (var sector in dlc_sectors)
{
dlc_Sector dlc_sector = new dlc_Sector
{
name = sector.name,
division_id = sector.Website.division_id
};
db.dlc_Sectors.AddObject(dlc_sector);
var dlc_products = db.Products.Where(p => p.Sectors
.Any(s => s.Website.division_id == dlc_sector.division_id && s.name == dlc_sector.name))
.DistinctBy(p => p.name).ToList();
foreach (var product in dlc_products.ToList())
{
var dlc_product = db.dlc_Products.SingleOrDefault(p => p.name == product.name);
if (dlc_product == null)
{
dlc_product = new dlc_Product { name = product.name };
db.dlc_Products.AddObject(dlc_product);
}
dlc_product.dlc_Sectors.Add(dlc_sector);
db.SaveChanges();
}
}
}
db.SaveChanges();
}
}
The first db.SaveChanges() is to make sure that a new product having the same name does not get inserted again.
How can I resolve this? Thanks in advance.
Worked for me:
var Local = db.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added)
.Where(es => es.Entity is dlc_Product).Select(es => es.Entity as dlc_Product);
var dlc_product = db.dlc_Products.SingleOrDefault(p => p.name == product.name)
?? Local.SingleOrDefault(p => p.name == product.name);
Thanks.

Not sure why this occurs, but the first SaveChanges() would not be necessary if you also checked the Local collection of db.dlc_Products:
foreach (var product in dlc_products.ToList())
{
var dlc_product = db.dlc_Products.SingleOrDefault(p => p.name == product.name)
?? db.dlc_Products.Local.SingleOrDefault(p => p.name == product.name);
...
}
New objects are added to the Local collection.
Note that db.dlc_Products.Join(db.dlc_Products.Local) looks more efficient, but it does not compile, and the other way around it queries the whole db.dlc_Products for each call.

Related

EF .Net Core Enumerable.Concat not working

Below is my code
var dbClaimLink = this.Context.Set<ClaimLink>();
var claims = await DbSet
.Include(claim => claim.Parent)
.Include(link => link.ParentLinks)
.ToListAsync();
var newClaimLink = await dbClaimLink.ToListAsync();
var processedClaims = claims.Select(x =>
{
var claimLinks = x.ParentLinks;
if (!claimLinks.Any())
{
return x;
}
var hiddenParents = claimLinks.Select(p => claims.Find(t => t.Id == p.ClaimLinkId));
x.HiddenParents = hiddenParents;
return x;
});
foreach (var objClaim in processedClaims)
{
if (objClaim.Children == null)
objClaim.Children = new List<Claim>();
var lst = newClaimLink.Where(k=> k.ClaimLinkId == objClaim.Id).ToList();
if (lst.Any())
{
foreach (var item in lst)
{
IEnumerable<Claim> newChildren = claims.Where(p => p.Id == item.ClaimId);
objClaim.Children.Concat(newChildren);
}
}
}
it always return old children set without concatenate with new children. I want to those old and new children set concatenate in side of foreach loop
the Concat method returns a new collection with both values and does not alter the original.
Concat will return new object - result of concatination, so you need to save it somewhere: var result = objClaim.Children.Concat(newChildren);
Where is lazy operation, it does not execute in place, only after materialization (ToArray, or foreach call): claims.Where(p => p.Id == item.ClaimId).ToArray()

Checking if item is null or if a table doesn't contain any matching data

I've got this query where I'm trying to check if there is an item in the table TruckItems that matches the string value in the variable tareTotal.
public QuoteResult GetTruckInformation(QuoteData data)
{
QuoteResult qr = null;
using (TruckDb db = new TruckDb())
{
var tareTotal = db.ChassisModel.Where(x => x.Id == data.ChassisId).FirstOrDefault();
var items = (from x in db.TruckItems where x.Model == tareTotal.Name select x); //Issue lies here
if (items.Any()) //Error here
{
var truckTareTotal = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault().TareTotal;
var truckGVM = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault().GVM;
var list = new QuoteResult
{
TareTotal = Convert.ToDouble(truckTareTotal),
GVM = Convert.ToDouble(truckGVM)
};
qr = list;
}
}
return qr;
}
I'm getting the error at if (items.Any()):
Non-static method requires a target.
I do not fully understand my problem and I can't find anything that might help me with my problem. Can someone please give me some pointers as to what I'm doing wrong with my variable items? Thank you!
EDIT:
Thanks to everyone for helping me! All of your coding works perfectly fine. I've found my issue and for some reason it has something to do with threading...
In my client side application I used the GetTruckInformation method in a combobox selection changed event and for some reason when it runs through that event, my server side application changes threads between all my statements, thus resulting in all of my data being null.
Here is my WPF/client side method just for show:
private async void cmbChassisModel_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
using (TruckServiceClient service = new TruckServiceClient())
{
QuoteData data = new QuoteData();
data.ChassisId = cmbChassisModel.GetDisplayItemId();
var items = await service.GetTruckInformationAsync(data);
if (items != null)
{
lblTareTotalAmount.Content = items.TareTotal;
lblGVMAmount.Content = items.GVM;
}
}
}
No one has to answer to this issue, I just wanted to let everyone know. :) I will try and figure out why this would happen. :)
Use a .ToList() on the items. Like this:
var items= db.TruckItems.Where(w=>w.Model == tareTotal.Name).ToList();
Otherwise you might run into troubles when executing .Any()
Edit:
Just for the sake of the expirment. Do this:
if(tareTotal==null)
throw new Exception("The tare total is null");
var items= db.TruckItems.Where(w=>w.Model == tareTotal.Name).ToList();
If no items match the db.ChassisModel.Where(x => x.Id == data.ChassisId) then tareTotal will be null.
Anyway, if you only want to check if db.TruckItems contains tareTotal.Name or not, use this. This also improve performance:
Change:
var items = (from x in db.TruckItems where x.Model == tareTotal.Name select x);
if (items.Any())
to:
if(db.TruckItems.Any(x => x.Model == tareTotal.Name))
Check this optimized method:
public QuoteResult GetTruckInformation(QuoteData data)
{
QuoteResult qr = null;
using (TruckDb db = new TruckDb())
{
var tareTotal = db.ChassisModel.Where(x => x.Id == data.ChassisId).FirstOrDefault();
if (tareTotal != null)
{
var item = db.TruckItems.Where(x => x.Model == tareTotal.Name).FirstOrDefault();
if (item != null)
{
var list = new QuoteResult
{
TareTotal = Convert.ToDouble(item.TareTotal),
GVM = Convert.ToDouble(item.GVM)
};
qr = list;
}
}
}
return qr;
}
Simple :
var hasItems = (from x in db.TruckItems where x.Model == tareTotal.Name select x).Any();
Will be tru if you have at least one item matching your condition.

Entity Framework condition in select

I have the following database code:
static IEnumerable<dynamic> GetData(bool withchildren) {
using (var model = new testEntities()) {
var res = default(IQueryable<dynamic>);
if (withchildren) {
res = model.UserSet
.Where(u => u.name != "")
.Select(u => new {
Name = u.name,
Email = u.email,
Groups = u.GroupSet.Select(g => new {
Name = g.name,
Id = g.Id
})
});
} else {
res = model.UserSet
.Where(u => u.name != "")
.Select(u => new {
Name = u.name,
Email = u.email
});
}
return res.ToList()
}
}
I would like to shrink the code and write it like this:
static IEnumerable<dynamic> GetData(bool withchildren) {
using (var model = new testEntities()) {
var res = default(IQueryable<dynamic>);
res = model.UserSet
.Where(u => u.name != "")
.Select(u => {
dynamic item = new {
Name = u.name,
Email = u.email
};
if(withchildren) {
item.Groups = u.GroupSet.Select(g => new {
Name = g.name,
Id = g.Id
});
}
return item;
});
return res.ToList();
}
}
But Visual Studio complains, that it cannot convert the lambda expression into an expression tree.
My question is, is there a way to accomplish that with the Entity Framework and Linq? I really wouldn't want to use ADO.net directly.
Maybe there is even a better version to shrink it, than the code that I imagine.
Here is a related question with Linq-To-Objects.
EDIT
Before someone asks, I use dynamic in the example code to make it a bit easier and faster.
EDIT 2
My goal with this approach is, to only query the fields I need to improve performance. Check http://www.progware.org/Blog/post/Slow-Performance-Is-it-the-Entity-Framework-or-you.aspx.
At the moment we use something like
static IEnumerable<dynamic> GetData(bool withchildren) {
using (var model = new testEntities()) {
var res = default(IQueryable<dynamic>);
res = model.UserSet
.Where(u => u.name != "")
.ToList();
return res;
}
}
And the performance is, according to Glimpse, horrible.
EDIT 3
Short side note, I made up some quick and dirty code. That is, why the foreach at the end was not needed. The actual code is not available at the moment.
Is there any reason you couldn't use:
res = model.UserSet
.Where(u => u.name != "")
.Select(u => new {
Name = u.name,
Email = u.email,
Groups = withchildren
? u.GroupSet.Select(g => new {
Name = g.name,
Id = g.Id
})
: null;
})
};
or perhaps:
res = model.UserSet
.Where(u => u.name != "")
.ToList() // ToList() here to enumerate the items
.Select(u => {
dynamic item = new {
Name = u.name,
Email = u.email
};
if(withchildren) {
item.Groups = u.GroupSet.Select(g => new {
Name = g.name,
Id = g.Id
});
}
return item;
});
One approach that would allow you to eliminate some code would be:
var res = model.UserSet.Where(u => u.name != "");
if (withchildren) {
res = res.Select(u => new {
Name = u.name,
Email = u.email,
Groups = u.GroupSet.Select(g => new {
Name = g.name,
Id = g.Id
})
});
} else {
res = res.Select(u => new {
Name = u.name,
Email = u.email
});
}
One of the most requested by community feature is support of multi-line expressions in EF,
however so far, you can use only conditional operator "?:" as well as wrap result in
one common type, so both your results will have to have "Groups" field.
Also there are an extensions to linq-providers such as https://www.nuget.org/packages/LinqKit/ ,
however they are based on own conventions so any developer should study it in depth before
taking advance in applying and supporting code written upon that extensions.

How can I delete multiple rows with Entity Framework?

I have this code but it doesn't work :
public bool DeleteAccess(int _UserID, IEnumerable<int> _ModulID)
{
MPortalContext db=new MPortalContext();
foreach (var item in _ModulID)
{
var validation = db.WebSite_PermissionDB.Where(x => x.UserID == _UserID && x.ModuleID == item);
db.WebSite_PermissionDB.Remove(validation);
}
db.SaveChanges();
return true;
}
my (_ModulID) is a collection of ids that i filter them and then with foreach delete them but it doesn't work ??
one way to delete is
context.Database.SqlQuery<WebSite_PermissionDB>(
"DELETE FROM Users WHERE UserID = #userId ",
new [] { new SqlParameter("#userId ", 1) }
);
First get the all entities that mathces with your condition, then use RemoveRange method:
var entities = db.WebSite_PermissionDB
.Where(x => x.UserID == _UserID && _ModulID.Contains(x.ModuleID));
db.WebSite_PermissionDB.RemoveRange(entities);
db.SaveChanges();
Also you might want to use using statement in order to make sure that your DbContext is Disposed properly.
using(MPortalContext db = new MPortalContext())
{
...
}
var distinctResult = db.WebSite_PermissionDB.Distinct();
db.WebSite_PermissionDB.RemoveRange(db.WebSite_PermissionDB.Except(distinctResult));
db.SaveChanges();
MPortalContext db=new MPortalContext();
foreach (var item in _ModulID)
{
var validation = db.WebSite_PermissionDB.Where(x => x.UserID == _UserID && x.ModuleID == item).FirstOrDefault();
db.WebSite_PermissionDB.Remove(validation);
db.SaveChanges();
}
return true;
I forget use .FirstOrDefault(); now correct. Thank friends.

How to Filter linq query

I am able to filter the data with the following two parameters id1 and id2, and get accurate result of 10 records, from which have 9 with a price_type=cs and other with price-type=ms.
However, if I add price_type to the parameters id1 and id2 (id1=23456,567890&id2=6782345&price_type=ms), I get 3000 records instead of getting one record.
Am I missing something in the code. Any help would be very much appreciated.
var data = db.database_BWICs.AsQueryable();
var filteredData = new List<IQueryable<database_Data>>();
if (!string.IsNullOrEmpty(query.name))
{
var ids = query.name.Split(',');
foreach (string i in ids)
{
filteredData.Add(data.Where(c => c.Name != null && c.Name.Contains(i)));
}
}
if (!string.IsNullOrEmpty(query.id2))
{
var ids = query.id2.Split(',');
foreach (string i in ids)
{
filteredData.Add(data.Where(c => c.ID2!= null && c.ID2.Contains(i)));
}
}
if (!string.IsNullOrEmpty(query.id1))
{
var ids = query.id1.Split(',');
foreach (string i in ids)
{
filteredData.Add(data.Where(c => c.ID1!= null && c.ID1.Contains(i)));
}
}
if (query.price_type != null)
{
var ids = query.price_type.Split(',');
foreach (string i in ids)
{
filteredData.Add(data.Where(c => c.Type.Contains(i)));
}
}
if (filteredData.Count != 0)
{
data = filteredData.Aggregate(Queryable.Union);
}
Updated Code:
var data = db.database_BWICs.AsQueryable();
if (!string.IsNullOrEmpty(query.name))
{
var ids = query.name.Split(',');
data = data.Where(c => c.Name != null && ids.Contains(c.Name));
}
if (query.price_type != null)
{
var ids = query.price_type.Split(',');
data = data.Where(c => ids.Contains(c.Cover));
}
if (!String.IsNullOrEmpty(query.id1))
{
var ids = query.id1.Split(',');
data = data.Where(c => c.ID1!= null && ids.Contains(c.ID1));
}
Because you don't add filter to restrict, every filter adds datas to result.
It means you make OR between your filters, not AND.
And your usage of contains looks rather strange too : you're using String.Contains, while I would guess (maybe wrong) that you want to see if a value is in a list => Enumerable.Contains
You should rather go for something like this (withoud filteredData)
var data = db.database_BWICs.AsQueryable();
if (!string.IsNullOrEmpty(query.name))
{
var ids = query.name.Split(',');
data = data.Where(c => c.Name != null && ids.Contains(c.Name)));
}
//etc.
if (query.price_type != null)
{
var ids = query.price_type.Split(',');
data = data.Where(c => ids.Contains(c.Type));
}
EDIT
Well, if you wanna mix and or conditions, you could go for PredicateBuilder
Then your code should look like that (to be tested).
//manage the queries with OR clause first
var innerOr = Predicate.True<database_BWICs>();//or the real type of your entity
if (!String.IsNullOrEmpty(query.id1))
{
var ids = query.id1.Split(',');
innerOr = innerOr.Or(c => c.ID1!= null && ids.Contains(c.ID1));
}
if (!String.IsNullOrEmpty(query.id2))
{
var ids = query.id2.Split(',');
innerOr = innerOr.Or(c => c.ID2!= null && ids.Contains(c.ID2));
}
//now manage the queries with AND clauses
var innerAnd = Predicate.True<database_BWICs>();//or the real type of your entity
if (query.price_type != null)
{
var ids = query.price_type.Split(',');
innerAnd = innerAnd.And(c => ids.Contains(c.Type));
}
//etc.
innerAnd = innerAnd.And(innerOr);
var data = db.database_BWICs.AsQueryable().Where(innerAnd);

Categories

Resources