Entity framework select an existing item and only pull back one of its fields to update - c#

I'm trying to do something that should be "simple", I want to pull out a piece of data from my database but I only want to pull out the description (the database table for this item has first name, last name, address etc etc).
So when I call my database call I want to just grab the description and then update it, I don't want to grab anything else as this will cost network power and may cause lag if uses multiple times in a few seconds.
Here is my code that i'm trying to fix
using (var context = new storemanagerEntities())
{
var stock = context.stocks.Where(x => x.id == model.Id).Select(
x => new stock()
{
description = x.description
}).FirstOrDefault();
stock.description = model.Description;
context.SaveChanges();
}
The error I am catching is this
**The entity or complex type 'StoreManagerModel.stock' cannot be constructed in a LINQ to Entities query.**
I'm sure using the "new" keyword is probably the problem, but does anyone have any ideas on how to solve this?
--update
This code works, but it doesn't seem to actually update the database
public void UpdateDescription(StockItemDescriptionModel model)
{
using (var context = new storemanagerEntities())
{
var stock = context.stocks.Where(x => x.id == model.Id)
.AsEnumerable()
.Select(
x => new stock
{
description = x.description
}).FirstOrDefault();
stock.description = model.Description;
context.SaveChanges();
}
}
At the moment it would seem it maybe my MySQl driver which is 6390, it seems to work in another version I tried, sorry I haven't found the answer yet

You can do it even without getting any entity from the database by creating a stub entity:
context.Configuration.ValidateOnSaveEnabled = false;
// Create stub entity:
var stock = new stock { id = model.Id, description = model.Description };
// Attach stub entity to the context:
context.Entry(stock).State = System.Data.Entity.EntityState.Unchanged;
// Mark one property as modified.
context.Entry(stock).Property("description").IsModified = true;
context.SaveChanges();
Validation on save is switched off, otherwise EF will validate the stub entity, which is very likely to fail because it may have required properties without values.
Of course it may be wise to check whether the entity does exist in the database at all, but that can be done by a cheap Any() query.

You can't project to a mapped entity type during an L2E query, you would need to switch the context back to L2F. For optimal performance it's recommended to use AsEnumerable over ToList to avoid materializing the query too early e.g.
var stock = context.stocks.Where(x => x.id == model.Id)
.AsEnumerable()
.Select(x => new stock
{
description = x.description
})
.FirstOrDefault();
As to your actual problem, the above won't allow you to do this as is because you have effectively created a non-tracking entity. In order for EF to understand how to connect your entity to your DB you would need to attach it to the context - this would require that you also pull down the Id of the entity though i.e.
Select(x => new stock
{
id = x.id,
description = x.description
})
...
context.stocks.Attach(stock);
stock.description = model.Description;
context.SaveChanges();

Related

LINQ troubles in C# using Entity Framework

I have a few tables and this is what I need to achieve.
This gets all the rows from one table
var FRA = from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
From within that, I get all the rows where ActTypeID.
Then I need to query another table from with the ID's get from that
foreach (var item in FRA)
{
var FRSA = _cctDBContext.Frsa
.Select(p => new { p.Fraid, p.Frsa1,
p.Frsaid, p.CoreId,
p.RelToEstId, p.ScopingSrc,
p.Mandatory })
.Where(p => p.Fraid == item.Fraid)
.ToList();
}
I then need to push each one of these to Entity Framework. I usually do it this way:
foreach (var item in FRA)
{
var FinanicalReportingActivity = new FinancialReportingActivity { FinancialReportingActivityId = item.Fraid, ScopingSourceType = item.ScopingSrc, Name = item.Fra1, MandatoryIndicator = item.Mandatory, WorkEffortTypeId = 0 };
_clDBContext.FinancialReportingActivity.AddRange(FinanicalReportingActivity);
}
But because I have used 2 for each loops, I cannot get the variables to work because I cannot find a way to get local variables as the entity context.
Can anyone think of a better way to code this?
Thanks
It looks like you can do this as a single join:
var query =
from prod in _cctDBContext.Fra
where prod.ActTypeId == 1
join p in _cctDBContext.Frsa on prod.Fraid equals p.Fraid
select new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
};
It looks like you are loading data from one set of entities from one database and want to create matching similar entities in another database.
Navigation properties would help considerably here. Frsa appear to be a child collection under a Fra, so this could be (if not already) wired up as a collection within the Fra entity:
Then you only need to conduct a single query and have access to each Fra and it's associated Frsa details. In your case you look to be more interested in the associated FRSA details to populate this ReportingActivity:
var details = _cctDBContext.Fra
.Where(x => x.ActTypeId == 1)
.SelectMany(x => x.Frsa.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
though if the relationship is bi-directional where a Fra contains Frsas, and a Frsa contains a reference back to the Fra, then this could be simplified to:
var details = _cctDBContext.Frsa
.Where(x => x.Fra.ActTypeId == 1)
.Select(p => new
{
p.Fraid,
p.Frsa1,
p.Frsaid,
p.CoreId,
p.RelToEstId,
p.ScopingSrc,
p.Mandatory
}).ToList();
Either of those should give you the details from the FRSA to populate your reporting entity.

I am trying to save information to two data tables using one service method using c#

Writing an app and I am trying to add on to the method where a user creates a new gift card. I added another column in my applicationuser table called TotalBalance that adds in the balances of each cards created. So I can get a new card to save to the gift card table but I want the gift card balance to be added to the 'Users total donation balance' in the application user table. The code I'm working with is below.
public bool CreateGiftCard(GiftCardCreateViewModel model)
{
using (var context = new ApplicationDbContext())
{
var company = context
.Company
.Where(e => e.CompanyName == model.CompanyName)
.FirstOrDefault();
var companyId = company.CompanyId;
var entity =
new GiftCard()
{
OwnerId = _userId,
Amount = model.Amount,
CardNumber = model.CardNumber,
DonationUtc = DateTime.Now,
CompanyId = companyId,
// Optional
ExpirationDate = model.ExpirationDate,
AccessNumber = model.AccessNumber
};
company.CompanyAmount = company.CompanyAmount + entity.Amount;
context.GiftCard.Add(entity);
return context.SaveChanges() == 1;
}
}
You might be doing this in entirely the wrong place. Rather than handling it in the application at the time of update, you could look at creating this as a calculated column in the database itself.
The details will depend upon which RDBMS you're using, you might like to add a tag to indicate this.
To more directly answer your question, it is not possible to update two tables in a single select statement.
Try adding this code to your method (I guessed at some of the attribute names, but you can get the idea):
var appuser = context
.ApplicationUser
.Where(e => e.UserId == _userId)
.FirstOrDefault();
appuser.TotalBalance += model.Amount;
context.ApplicationUser.Update(appuser);

How effectively add not existing entities from input List to DB in Entity Framework

I have an entity User with primary key property UCO.
I would like to write a method AddUsers that adds all users from given list to the database. Problem is that when admin tries to add list in which is a user that already exists in the database, then an exception is thrown.
My solution that adds only Users that are not in database is here:
public void AddUsers(List<UserDTO> users)
{
using (var db = new AppDbContext())
{
var existingUsers = Mapper.Map<List<UserDTO>>(db.Users.ToList());
db.Users.AddRange(
Mapper.Map<List<User>>(users
.Where(user => !existingUsers
.Select(u => u.UCO)
.Contains(user.UCO))));
db.SaveChanges();
}
}
I would like to ask whether there is some more effective solution. If I had 10'000 users, then this would be very slow...
Thank you for answers :)
If the users list is not expected to be so big, you can avoid loading the potentially big existingUsers list at least in a two ways.
First, execute a single db query per each item in the users list (so totally users.Count queries):
using (var db = new AppDbContext())
{
db.Users.AddRange(Mapper.Map<List<User>>(users
.Where(user => !db.Users.Any(u => u.UCO == user.UCO))));
db.SaveChanges();
}
Second, execute a single db query for retrieving the subset of the UCO of the items from users list that exists in the database, then use it for excluding them from add:
using (var db = new AppDbContext())
{
var userUCOs = users.Select(u => u.UCO);
var existingUserUCOs = new HashSet<int>(db.Users
.Where(u => userUCOs.Contains(u.UCO))
.Select(u => u.UCO));
db.Users.AddRange(Mapper.Map<List<User>>(users
.Where(u => !existingUserUCOs.Contains(u.UCO))));
db.SaveChanges();
}
(if the UCO type is not int, just use HashSet<UCO_Type>)

Remove a record in entity framework

I'm working with entity framework for sometimes now and one thing that really irritates me is the fact that to delete an item we have to find the object and then remove it. so if we have the PK of the record we have to get the object and then remove the object.
ex:
Category category = db.Categories.Find(categoryId);
db.Categories.Remove(category);
db.SaveChages();
In this method we are hitting database twice..!!!
is there a way to remove the record with just hitting the database once?
For those none-believers this is the glimpse out come: :)
// no trip to database
var rec = db.TableName.Local.SingleOrDefault(r => r.Id == primaryKey);
if (rec == null) throw NotFoundOrWhateverException();
// still no trip to database, if I remember right
db.TableName.Remove(rec);
// trip to database
db.SaveChanges();
IF you don't want to get the complete object you can try this way using the primary key property of it:
Category category = new Category () { Id = categoryId } ;
db.Categories.Attach(category);
db.DeleteObject(category);
db.Savechanges();
If you are using EF 5 then you can use EntityFramework.Extended Library using NUGETand can do like this:
db.Categories.Delete(c => c.Id == categoryId);
[Answer turned out to be incorrect. Removed content to keep from confusing others. Kept the post for comment thread.]

What is the recommended practice to update or delete multiple entities in EntityFramework?

In SQL one might sometimes write something like
DELETE FROM table WHERE column IS NULL
or
UPDATE table SET column1=value WHERE column2 IS NULL
or any other criterion that might apply to multiple rows.
As far as I can tell, the best EntityFramework can do is something like
foreach (var entity in db.Table.Where(row => row.Column == null))
db.Table.Remove(entity); // or entity.Column2 = value;
db.SaveChanges();
But of course that will retrieve all the entities, and then run a separate DELETE query for each. Surely that must be much slower if there are many entities that satisfy the criterion.
So, cut a long story short, is there any support in EntityFramework for updating or deleting multiple entities in a single query?
EF doesn't have support for batch updates or deletes but you can simply do:
db.Database.ExecuteSqlCommand("DELETE FROM ...", someParameter);
Edit:
People who really want to stick with LINQ queries sometimes use workaround where they first create select SQL query from LINQ query:
string query = db.Table.Where(row => row.Column == null).ToString();
and after that find the first occurrence of FROM and replace the beginning of the query with DELETE and execute result with ExecuteSqlCommand. The problem with this approach is that it works only in basic scenarios. It will not work with entity splitting or some inheritance mapping where you need to delete two or more records per entity.
Take a look to Entity Framework Extensions (Multiple entity updates). This project allow set operations using lambda expressions. Samples from doc:
this.Container.Devices.Delete(o => o.Id == 1);
this.Container.Devices.Update(
o => new Device() {
LastOrderRequest = DateTime.Now,
Description = o.Description + "teste"
},
o => o.Id == 1);
Digging EFE project source code you can see how automatize #Ladislav Mrnka second approach also adding setting operations:
public override string GetDmlCommand()
{
//Recover Table Name
StringBuilder updateCommand = new StringBuilder();
updateCommand.Append("UPDATE ");
updateCommand.Append(MetadataAccessor.GetTableNameByEdmType(
typeof(T).Name));
updateCommand.Append(" ");
updateCommand.Append(setParser.ParseExpression());
updateCommand.Append(whereParser.ParseExpression());
return updateCommand.ToString();
}
Edited 3 years latter
Take a look to this great answer: https://stackoverflow.com/a/12751429
Entity Framework Extended Library helps to do this.
Delete
//delete all users where FirstName matches
context.Users.Delete(u => u.FirstName == "firstname");
Update
//update all tasks with status of 1 to status of 2
context.Tasks.Update(
t => t.StatusId == 1,
t2 => new Task {StatusId = 2});
//example of using an IQueryable as the filter for the update
var users = context.Users.Where(u => u.FirstName == "firstname");
context.Users.Update(users, u => new User {FirstName = "newfirstname"});
https://github.com/loresoft/EntityFramework.Extended

Categories

Resources