I have a WPF app running against DB2 9.1 (z/OS) using EF5. Everything works fine except for inserting where the primary key is an INTEGER(10) field.
The entity has the mapped property as an int type.
private Models.UserInfo GetUserInfo(String emplID, String firstName, String lastName)
{
if (String.IsNullOrEmpty(emplID))
return null;
int _emplID = Convert.ToInt32(emplID.Trim());
try
{
using (var ctx = new Data.TIMSContext())
{
var user = (from u in ctx.Query<Data.Entities.ASNUser>()
where u.EmployeeID == _emplID
select u).FirstOrDefault();
if (user == null)
{
//add user to database
user = new Data.Entities.ASNUser()
{
EmployeeID = _emplID,
FirstName = firstName.Trim(),
LastName = lastName.Trim()
};
ctx.Set<Data.Entities.ASNUser>().Add(user);
ctx.SaveChanges();
}
return new Models.UserInfo()
{
EmployeeID = user.EmployeeID,
DisplayName = String.Format("{0}, {1}", user.LastName, user.FirstName)
};
}
}
catch (Exception e)
{
throw;
}
}
This could be a problem with your edmx file / EF model.
If the EmployeeID field is defined in the model as a auto increment id, then EF will ignore the value that you set and null will be sent to the database. But the database does not have an auto increment field, so it tries to insert null.
Related
I am having some issues with an edit form that does not seem to work no matter what I use.
I have tried
[ReadOnly(true)] and [Editable(false)]
in the Model
#Html.EditorFor(model => model.SellingPrice, new { htmlAttributes = new { #class = "form-control", #readonly = true } })
in the View..
I have changed the controller with nothing about the field.
I have also tried changing the model to
{ get; private set; }
According to a other post on another site using the [ReadOnly(true)] in the model and nothing in the controller pointing to it, it should come up 'null' and it does not. It seems to give a value of 0 or what the field has in it. Depending on if I use it in the edit View or not.
This field in the table is a calculated field on the SQL side. Used only for viewing.
Below is the controller POST - 2 Versions that I have tried:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ProductMaster productMaster)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
try
{
if (ModelState.IsValid)
{
ProductMaster prodFromDB = db.ProductMaster.Single(x => x.ProductMasterId == productMaster.ProductMasterId);
prodFromDB.VendorId = productMaster.VendorId;
prodFromDB.Material = productMaster.Material;
prodFromDB.VendorRef = productMaster.VendorRef;
prodFromDB.CreatedDate = productMaster.CreatedDate;
prodFromDB.CreatedBy = productMaster.CreatedBy;
prodFromDB.LastUpdated = productMaster.LastUpdated;
prodFromDB.UpdatedBy = productMaster.UpdatedBy;
prodFromDB.UnitOfMeasure = productMaster.UnitOfMeasure;
prodFromDB.StandardCost = productMaster.StandardCost;
prodFromDB.AverageCost = productMaster.AverageCost;
prodFromDB.LastCost = productMaster.LastCost;
prodFromDB.IsPrimary = productMaster.IsPrimary;
var Manager = ((IObjectContextAdapter)db).ObjectContext.ObjectStateManager;
Manager.ChangeObjectState(prodFromDB, System.Data.Entity.EntityState.Modified);
db.SaveChanges();
sb.Append("Submitted");
return Content(sb.ToString());
}
else
{
foreach (var key in this.ViewData.ModelState.Keys)
{
foreach (var err in this.ViewData.ModelState[key].Errors)
{
sb.Append(err.ErrorMessage + "<br/>");
}
}
}
}
catch (Exception ex)
{
sb.Append("Error :" + ex.Message);
}
return Content(sb.ToString());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ProductMasterId,VendorId,Material,VendorRef,CreatedDate,CreatedBy,LastUpdated,UpdatedBy,UnitOfMeasure,StandardCost,AverageCost,LastCost,IsPrimary")] ProductMaster productMaster)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
try
{
if (ModelState.IsValid)
{
db.Entry(productMaster).State = EntityState.Modified;
db.SaveChanges();
sb.Append("Submitted");
return Content(sb.ToString());
}
else
{
foreach (var key in this.ViewData.ModelState.Keys)
{
foreach (var err in this.ViewData.ModelState[key].Errors)
{
sb.Append(err.ErrorMessage + "<br/>");
}
}
}
}
catch (Exception ex)
{
sb.Append("Error :" + ex.Message);
}
return Content(sb.ToString());
}
The error that I get is:
The column "SellingPrice" cannot be modified because it is either a computed column or is the result of a UNION operator
First thing would be to mark the Entity property with the DatabaseGeneratedOption of Computed:
public class Product
{
// ...
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public decimal SellingPrice { get; internal set; }
// ...
}
The next thing would be to avoid code that sets an entity's EntityState to modified explicitly. So long as the DbContext is tracking the entity, this should be enough:
ProductMaster prodFromDB = db.ProductMaster.Single(x => x.ProductMasterId == productMaster.ProductMasterId);
prodFromDB.VendorId = productMaster.VendorId;
prodFromDB.Material = productMaster.Material;
prodFromDB.VendorRef = productMaster.VendorRef;
prodFromDB.CreatedDate = productMaster.CreatedDate;
prodFromDB.CreatedBy = productMaster.CreatedBy;
prodFromDB.LastUpdated = productMaster.LastUpdated;
prodFromDB.UpdatedBy = productMaster.UpdatedBy;
podFromDB.UnitOfMeasure = productMaster.UnitOfMeasure;
prodFromDB.StandardCost = productMaster.StandardCost;
prodFromDB.AverageCost = productMaster.AverageCost;
prodFromDB.LastCost = productMaster.LastCost;
prodFromDB.IsPrimary = productMaster.IsPrimary;
db.SaveChanges();
The reason is that lets say I have an entity with 20 columns and I update 5 of them from the view model, and only 2 of those values actually differ from the entity's current state. If I let the DbContext track the changes and just call SaveChanges then the resulting UPDATE SQL statement will be an update specifying just the columns which values actually changed. If instead I set the EntityState to Modified, the UPDATE SQL statement will include all columns, whether I set them or not, and whether they actually changed or not. Computed columns should be ignored, but why incur the cost/risk of updating/overwriting values you don't intend to have been changed?
I am an old hand at ADO.NET but new to linq. I have written the below function to change one column of int in the database to a new value. The query part works fine, but after me updating the KeyStates in the database doesn't seem to work. Nothing changes. No errors, but also no update.
public static void UpdateKeySetToDatabase(IChangeTrackableAsSet set,
int tableId, State newState)
{
try
{
using (var c = new SqlConnection(ConnectionString.ConnectionString))
{
c.Open();
List<int> keyList = set.trackedKeys.Select(k => k.KeyId).ToList();
DataContext dc = new DataContext(c);
Table<TrackedKey> tableKeys = dc.GetTable<TrackedKey>();
var KeyStates =
from k in tableKeys
where (keyList.Contains(k.KeyId) && k.TableId == tableId)
select k;
foreach (var k in KeyStates)
{
EventHandling.Logging.CreateTextEvent($"Key {k.ShowKeyAsJson()}");
k.StatusOfKey = (int)newState;
EventHandling.Logging.CreateTextEvent($"New Key {k.ShowKeyAsJson()}");
};
tableKeys.Context.SubmitChanges();
}
}
catch (Exception ex)
{
EventHandling.Logging.CreateTextEvent($"linq error {ex.ToString()}");
}
}
I think you should specify to the Entity Framework context, that the entity has changed, in order to update it.
...
k.StatusOfKey = (int)newState;
EventHandling.Logging.CreateTextEvent($"New Key {k.ShowKeyAsJson()}");
dc.Entry(k).State = EntityState.Modified;
...
When you execute the SaveChanges() method, all your objects will be modified.
I want to upsert reference members of an existing entity.
Do I have to write specific code for the upsert?
meaning: I have to check if I'm handling an existing reference member or a new one.
Is there any other simple way to do so?
What happens when you do only Save ?
public void SaveCofiguration(MamConfiguration_V1Ui itemUi)
{
var itemEf = mMamConfiguration_V1UiToEfConvertor.ConvertToNewEf(itemUi);
using (var maMDBEntities = new MaMDBEntities())
{
IDal<MamConfiguration_V1> mamConfigurationDal = mDalFactory.GetDal<MamConfiguration_V1>(maMDBEntities);
mamConfigurationDal.Save(itemEf);
}
}
public MamConfiguration_V1 GetById(object id)
{
id.ThrowIfNull("id");
int configurationId = Convert.ToInt32(id);
var result =
mMaMDBEntities.MamConfiguration_V1.SingleOrDefault(item => item.ConfigurationId == configurationId);
return result;
}
public MamConfiguration_V1 Save(MamConfiguration_V1 item)
{
item.ThrowIfNull("item");
var itemFromDB = GetById(item.ConfigurationId);
if (itemFromDB != null)
{
UpdateEfItem(itemFromDB, item);
// if (mMaMDBEntities.ObjectStateManager.GetObjectStateEntry(itemFromDB).State == EntityState.Detached)
// {
// mMaMDBEntities.MamConfiguration_V1.AddObject(itemFromDB);
// }
// Attached object tracks modifications automatically
mMaMDBEntities.SaveChanges();
return item;
}
private void UpdateEfItem(MamConfiguration_V1 itemFromDb, MamConfiguration_V1 itemFromUi)
{
itemFromDb.UpdatedDate = DateTime.Now;
itemFromDb.Description = itemFromUi.Description;
itemFromDb.StatusId = itemFromUi.StatusId;
itemFromDb.Name = itemFromUi.Name;
itemFromDb.NumericTraffic = itemFromUi.NumericTraffic;
itemFromDb.PercentageTraffic = itemFromUi.PercentageTraffic;
itemFromDb.Type = itemFromUi.NumericTraffic;
foreach (var item in itemFromDb.MamConfigurationToBrowser_V1.ToList())
{
if (itemFromUi.MamConfigurationToBrowser_V1.All(b => b.BrowserVersionId != item.BrowserVersionId))
{
mMaMDBEntities.MamConfigurationToBrowser_V1.DeleteObject(item);
}
}
for (int i = 0; i < itemFromUi.MamConfigurationToBrowser_V1.Count; i++)
{
var element = itemFromUi.MamConfigurationToBrowser_V1.ElementAt(i);
var item = itemFromDb.MamConfigurationToBrowser_V1.SingleOrDefault(b => b.BrowserVersionId == element.BrowserVersionId);
if (item != null)
{
// copy properties from element to item
}
else
{
element.Browser = mMaMDBEntities.Browsers.Single(browserItem =>
browserItem.BrowserID == element.BrowserID);
//element.MamConfiguration_V1 = itemFromDb;
//have also tried: element.MamConfiguration_V1 = null;
//element.MamConfiguration_V1Reference = null;
itemFromDb.MamConfigurationToBrowser_V1.Add(element);
}
}
}
But I would have expecte Save(itemUi) and SaveChanges() to work fine. No?
public void InsertOrUpdate(DbContext context, UEntity entity)
{
context.Entry(entity).State = entity.Id == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
http://forums.asp.net/t/1889944.aspx/1
To avoid the overhead of a query and then insert, or throwing exceptions, you can take advantage of the underlying database support for merges or upserts.
This nuget package does the job pretty well: https://www.nuget.org/packages/FlexLabs.EntityFrameworkCore.Upsert/
Github: https://github.com/artiomchi/FlexLabs.Upsert
Example:
DataContext.DailyVisits
.Upsert(new DailyVisit
{
// new entity path
UserID = userID,
Date = DateTime.UtcNow.Date,
Visits = 1,
})
// duplicate checking fields
.On(v => new { v.UserID, v.Date })
.WhenMatched((old, #new) => new DailyVisit
{
// merge / upsert path
Visits = old.Visits + 1,
})
.RunAsync();
The underlying generated sql does a proper upsert. This command runs right away and does not use change tracking, so that is one limitation.
See 'AddOrUpdate' method of System.Data.Entity.Migrations.
http://msdn.microsoft.com/en-us/library/system.data.entity.migrations.idbsetextensions.addorupdate%28v=vs.103%29.aspx
using System.Data.Entity.Migrations;
public void Save(Person person) {
var db = new MyDbContext();
db.People.AddOrUpdate(person);
db.SaveChanges();
}
"optimistic" approach for simple scenarios (demos)...
dbContext.Find()'s intellisense help tells us that it either retrieves entity by key if already present in current context, or queries the database to get it... then we know if it exists to either add or update. i'm using EFCore v2.2.0.
var existing = _context.Find<InventoryItem>(new object[] {item.ProductId});
if (existing == null) _context.Add(item);
else existing.Quantity = item.Quantity;
_context.SaveChanges();
DbContext.Update Method
For entity types with generated keys if an entity has its primary key value set then it will be tracked in the Modified state. If the primary key value is not set then it will be tracked in the Added state. This helps ensure new entities will be inserted, while existing entities will be updated. An entity is considered to have its primary key value set if the primary key property is set to anything other than the CLR default for the property type.
For entity types without generated keys, the state set is always Modified.
read this article
you can use this sample
I looked all over the internet and still couldn't find a solution to this.
I tried the attach method:
public static void updatePhoto(string name, string albumName, string newName, string newPath)
{
//updates photo... no delete and adding...
var photo = new Image(){Label=newName, Path = newPath};
using (var db = new EzPrintsEntities())
{
db.Images.Attach(photo);
db.SaveChanges();
}
}
but that did not do anything at all.
So the question then is how do you implement an UPDATE to the sql database through EF in the code below?
public static void updatePhoto(string name, string albumName, string newName, string newPath)
{
EzPrintsEntities db = new EzPrintsEntities();
}
If you're updating an existing photo, you need to load it, and change the existing value:
public static void updatePhoto(string name, string albumName, string newName, string newPath)
{
using (var db = new EzPrintsEntities())
{
// Load photo
var photo = db.Images.FirstOrDefault(i => i.Label == name && i.Album == albumName);
if (photo == null)
{
// no matching photo - do something
}
// Update data
photo.Label = newName;
photo.Path = newPath;
db.SaveChanges();
}
}
The simplist way would be:
public static void updatePhoto(string name, string albumName, string newName, string newPath)
{
//updates photo... no delete and adding...
using (var db = new EzPrintsEntities())
{
var photo = (from p in db.Images
where p.name == name &&
p.albumname == albumName
select p).First();
photo.name = newName;
photo.path = newPath;
db.SaveChanges();
}
}
You simply select the existing photo object using Linq, modify it, and SaveChanges()
What you want to do is also pass to your updatePhoto method the value(s) for the primary key on your Image entity. Then instead of creating a new Image entity and attaching it and saving the context, you'll get the Image entity from your context, and just update the properties on it.
Something along these lines:
using (var db = new EzPrintsEntities())
{
var image = db.Images.SingleOrDefault(i => i.Id == id); // Assuming Id is the PK on Image, and we sent in the PK in a variable called id.
if (image != null)
{
image.Label = newName;
image.Path = newPath;
db.SaveChanges();
}
else
{
// Invalid PK value sent in, do something here (logging, error display, whatever).
}
}
I want to input data into my table (sql 2008) using linq to sql:
public static bool saveEmail(Emailadressen email)
{
TBL_Emailadressen saveMail = new TBL_Emailadressen();
destil_loterijDataContext db = new destil_loterijDataContext();
saveMail.naam = email.naam;
saveMail.emailadres = email.emailadres;
saveMail.lotnummer = email.lotnummer;
try
{
saveMail.naam = email.naam;
saveMail.lotnummer = email.lotnummer;
saveMail.emailadres = email.emailadres;
db.TBL_Emailadressens.InsertOnSubmit(saveMail);
return true;
}
catch (Exception ex)
{
Console.WriteLine("Opslaan niet gelukt!" + ex.ToString());
return false;
}
}
For some reason nothing is being added to this table.
My table has the following fields:
ID (Auto incr int)
Naam (varchar50)
lotnummer (varchar50)
emailadres (varchar50)
My object im trying to save (saveMail) always has an ID = 0 , and i don't know why. I think that is preventing me from saving to the DB?
Be sure to call SubmitChanges on your DataContext-derived class:
using(var dc = new MyDataContext())
{
saveEmail(new Emailadressen(...));
dc.SubmitChanges();
}