SaveChanges problem in N-Tier Architecture - c#

Normally, with MVC I use db.savechanges() method after I do some processes. But check the below code when I use N-Tier Architecture in everyloop its gonna insert in this way but I dont want it. I have to check all the items first. If there is no problem then I have to insert it all together.
foreach (var item in mOrderList)
{
MOrder mOrder = new MOrder();
mOrder.StatusAdmin = false;
mOrder.Date = DateTime.Now;
mOrder.StatusMVendor = "Sipariş alındı.";
mOrder.HowMany = item.HowMany;
mOrder.MBasketId = item.MBasketId;
mOrder.MProductId = item.MProductId;
mOrder.MVendorId = item.MVendorId;
mOrder.WInvestorId = item.WInvestorId;
MProduct mprostock = _imProductService.GetMProductById(item.MProductId);
if (mprostock.Stock<=0)
{
return ReturnErrorAndSuccess(HttpStatusCode.NotFound, "MProduct", mprostock.Name + " ürününde stok kalmadığı için işlem tamamlanamadı.");
}
_imOrderService.InsertMOrder(mOrder);
}

all you have to do is:
first you should define a method that get list of mProductId and then return list of MProduct.
after that you should check if there is any record with Stock<=0 then return your error.
-also for your insert you should define a method that get list of MOrder and return appropriate datatype for example Boolean.
public List<MProduct> GetMProductByIds(List<MProductId> mProductId)
{
//getting record code
}
public bool AddMOrder(List<MOrder> mOrder)
{
//inserting record code
}

Related

The property 'ID" is part of the object's key on INSERT

We have to transfer data from one database to another. So I tried to write a program, which reads tables from the old database, create Entities and store them afterwards in the new database. At the beginning it worked very good. I tried to read only one table and transfer it to the new one. Now i receive the following error:
"The property 'Id' is part of the object's key information and cannot
be modified.
No I dont get rid of that error. Even if I try to get back to the first implementation (which worked like a charm).Here I have the definition of the Table:
Table definition
And here the code:
class MappingUtility
{
public static IEnumerable<Nation> MapNation(DataTable table, IModelFactoryService service)
{
IEnumerable<DataRow> rows = table.AsEnumerable();
Nation nat = service.Create<Nation>();
foreach(var nation in rows)
{
nat.Id = (System.Guid)nation.ItemArray[0];
nat.HVCode = (string)nation.ItemArray[1];
nat.Kurzbezeichung = (string)nation.ItemArray[2];
nat.KFZ = (string)nation.ItemArray[3];
nat.iso_a2 = (string)nation.ItemArray[4];
nat.iso_a3 = (string)nation.ItemArray[5];
nat.iso_n3 = (string)nation.ItemArray[6];
nat.Vollbezeichung = (string)nation.ItemArray[7];
nat.Updated = DateTime.Now;
nat.Created = DateTime.Now;
yield return nat;
}
}
}
using (var da = new SqlDataAdapter("SELECT * FROM NATION", "....."))
{
var table = new DataTable();
da.Fill(table);
using (var context = new DAtenbankContext())
{
int i = 0;
foreach (var nation in MappingUtility.MapNation(table, ef6))
{
Debug.WriteLine(i++);
if (context.Nation.Where(p => p.Id == nation.Id).FirstOrDefault() == null)
{
try
{
context.Entry(nation).State = EntityState.Added;
context.SaveChanges();
}
catch(DbEntityValidationException ex)
{
Debug.WriteLine("");
}
catch (DbUpdateException ex)
{
Debug.WriteLine("There where some duplicate columns in the old table.");
Debug.WriteLine(ex.StackTrace);
}
}
}
}
}
Note: The id is not autogenerated. If I try to create only one Nation at a time i can insert it. Even with this for loop I insert one nation, at the second iteration I get the error.
I suspect that you're operating on the same instance of Nation with every iteration of the loop. It appears that you only ever create one instance and then modify it over time. Entity Framework is trying to track that instance, so modifying the key is confusing it.
Move the instantiation into the loop so that you're creating new instances:
IEnumerable<DataRow> rows = table.AsEnumerable();
foreach(var nation in rows)
{
Nation nat = service.Create<Nation>();
// ...
yield return nat;
}

Xamarin.Android SQLite SQLiteConnection.Insert does not return inserted object's ID

I'm very new to Xamarin and C# and trying to insert some sample data to my simple recipe database for testing purpourses.
However, when inserting a new recipe, the SQLiteConnection.Insert(data) does not return the ID of the inserted record as it should (see here), but instead returns 1 every time.
My insert data method:
public static int insertUpdate(Object data) {
string path = DB.pathToDatabase ();
DB.createDatabase ();
try {
var db = new SQLiteConnection(path);
int inserted = db.Insert(data);
if (inserted != 0)
inserted = db.Update(data);
return inserted;
}
catch (SQLiteException ex) {
return -1;
}
}
Inserting the sample data:
int stand = insertUpdate (new Recipe {
Name = "Standard",
Author = "Aeropress Nerd",
Description = "The perfect recipe for your first cup",
Type = "Default"
});
insertUpdate (new Step { Action = "Pour", Duration = 10, Recipe = stand });
insertUpdate (new Step { Action = "Stir", Duration = 20, Recipe = stand });
insertUpdate (new Step { Action = "Steep", Duration = 15, Recipe = stand });
int inv = insertUpdate (new Recipe {
Name = "Inverted",
Author = "Aeropress Nerd",
Description = "A more advanced brew using the inverted method.",
Type = "Default"
});
I cannot figure out what I am doing wrong. Thanks in advance for any help and sorry for the (probably) stupid question.
However, when inserting a new recipe, the SQLiteConnection.Insert(data) does not return the ID of the inserted record as it should (see here), but instead returns 1 every time.
I am pretty sure you downloaded some nuget package or component to include SQLite functionality to your Xamarin.Android App and it may be slightly different from the native implementation. Then, you should refer to the specific documentation for whatever it is that you're using on Xamarin.
My wild guess is that you are using this component. If I'm wrong, please comment to correct my answer. If I'm right, you should try this:
The object you want to insert
class Row
{
public int Id { get; set; }
}
class Recipe : Row
{
//Recipe's properties
}
class Step : Row
{
//Step's properties
}
The insertUpdate method definition
public static int insertUpdate(Row data) {
string path = DB.pathToDatabase ();
DB.createDatabase ();
try {
var db = new SQLiteConnection(path);
int inserted = db.Insert(data); //will be 1 if successful
if (inserted > 0)
return data.Id; //Acording to the documentation for the SQLIte component, the Insert method updates the id by reference
return inserted;
}
catch (SQLiteException ex) {
return -1;
}
}
The insertUpdate method usage
//As Step and Recipe both are derived classed from Row, you should be able to use insertUpdate indistinctively and without casting
insertUpdate (new Step { Action = "Steep", Duration = 15, Recipe = stand });
int inv = insertUpdate (new Recipe {
Name = "Inverted",
Author = "Aeropress Nerd",
Description = "A more advanced brew using the inverted method.",
Type = "Default"
});
why after inserting data to your db, you starting to update it by the same object right away. This code most likely redundant.
if (inserted != 0)
inserted = db.Update(data);
return inserted;

How can I edit or add to a particular field without pull the all object

How I can do just this ( a.myFavorits.Add()) without pulling the all object to var a , because a has a lot of data, and I don't want to pull all a object, but I can't find a way do do it.
I want to do the lambada and the linq without return something but linq is always return something
public static void addFavorits(long f,long idUser)
{
using (var db = dataBase())
{
// here i pull object user from users table
var a = db.users.Where(c => c.id == idUser).SingleOrDefault();
// here i adding to the object field myFavorits new value
//myFavorits is also a table of entitys that connected to user object
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.SaveChanges();
}
}
I thought to do something like this but i dont know how to set the field users_TableId that is the key that connect the 2 tables
public static void addFavorits(long favoritId,long idUser)
{
using (var db = dataBase())
{
db.favoritsUsersLong.Add(new BE.FavoritsUsersLong {myLong = favoritId}
/*,users_TableId =idUser*/);
db.SaveChanges();
}
}
Here's a concrete example that does what you want. In this example, only the Name of a Company is modified and saved. Or an item is added to one of its collections.
var cmp = new Company{ CmpId = 1, Name = "Cmp1" }; // CmpId is the primary key
db.Companies.Attach(cmp);
db.Entry(cmp).Property(c => c.Name).IsModified = true;
// Or add an entity to a collection:
cmp.Users = new[] {new User { Name = "a1", PassWord = "a1" } };
try
{
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}
finally
{
db.Configuration.ValidateOnSaveEnabled = true;
}
Result in SQL:
DECLARE #0 VarChar(30) = 'Cmp1'
DECLARE #1 Int = 1
UPDATE [dbo].[Company]
SET [Name] = #0
WHERE ([CmpId] = #1)
There are a few things to note here:
Obviously you need to know the Id of the entity you want to modify.
The object you create is called a stub entity, which is an incomplete entity. When you try to save such an entity, EF is very likely to complain about null values in required properties. That's why almost certain you'd have to disable validation (temporarily, or, better, dispose the context immediately).
If you want to add an item to a collection, you should leave validation enabled, because you'd want to know for sure that the new entity is valid. So you shouldn't mix these two ways to use a stub entity.
If you often need roughly the same small part of your entity you may consider table splitting.
I'm guessing this is what you want? I don't see you 'editting' I only see you adding.
using (var db = dataBase())
{
var a = new user();
....
//set properties etc..
...
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.users.Add(a);
db.SaveChanges();
}

Duplicate record in database when call SaveChanges()

Hi i have a problem with EF. In my application i have to load from database some content to populate a DataGrid.
UserControl :
contenus = new List<Contenu>();
contenus = sacoche.Contenus.ToList(); // i get sacoche in the parameter of the contructor
ContenuViewSource.Source = contenus;
ContenuView = (ListCollectionView)ContenuViewSource.View;
ContenuView.Refresh();
everything work just fine, but when i try to add some others Contenus i get a duplicate record in the database. The only difference between the duplicated record is that the first record loose his foreign key.
Here i add my Contenuto my Sacoche:
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
editableSacoche.Contenus = contenus;
SacocheDal.dbContext.SaveChanges();
all i do is get the Sacoche and add to it his Contenu and finally call SaveChanges().
Here is the result :
EDIT: I tried to get only the new items but failed.
List<Contenu> contenuAjoute = contenus.Except(editableSacoche.Contenus.ToList()).ToList();
in contenuAjoutei get all the records even if they are equal ...
Try this:
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
editableSacoche.Contenus = null;
editableSacoche.ContenusID = contenus.ID;
SacocheDal.dbContext.SaveChanges();
I found a way to achieve what i wanted. I create an ItemComparer and use Exceptto only add the new items.
Here is the comparer :
class ContenuComparer : IEqualityComparer<Contenu>
{
public bool Equals(Contenu x, Contenu y)
{
if (x.ContenuID == y.ContenuID)
return true;
return false;
}
public int GetHashCode(Contenu obj)
{
return obj.ContenuID.GetHashCode();
}
}
And Here the code :
editableSacoche = SacocheDal.dbContext.Sacoches.Include("Contenus").First(i => i.SacocheID == editableSacoche.SacocheID);
List<Contenu> contenuAjoute = contenus.Except(editableSacoche.Contenus.ToList(), new ContenuComparer()).ToList();
foreach (Contenu c in contenuAjoute)
{
editableSacoche.Contenus.Add(c);
}
SacocheDal.dbContext.SaveChanges();
I don't now if it's the right way but it works fine.

How to requery updated values immediately after update procedure runs

As far as I can tell, changes made to the database by the following code to "MySite" are immediate:
public List<vcData> UpdateDisplayAndUrl(List<vcData> vcDataList)
{
foreach (vcData vcData in vcDataList)
{
_entities.ExecuteStoreCommand("UPDATE vcData SET DisplayItem = {0}, DisplayUrl = {1} WHERE ID = {2} ", vcData.DisplayItem, vcData.DisplayUrl, vcData.ID);
}
return GetTableData();
}
What I would like to do is to immediately return the newly updated records for further processing, essentially, re-query the changes that have just been made:
public List<vcData> GetTableData()
{
var result = (from td in _entities.vcData
where td.SiteID == "MySite"
select td).ToList();
return result;
}
In my controller code, I am trying to do something like:
_currentvcTickerDataList = Repository.UpdateDisplayAndUrl(vcUnupdatedDataList);
//.....do more stuff with _currentvcTickerDataList, which ought to contain updated information, should it not?
PROBLEM: the GetTableData() method does not seem to return the updated values, only the previous (unupdated) values.
I am new to LINQ, entity framework, and MVC, so I'm pretty certain there is something fundamental that I am missing.
You need to set the MergeOption to OverwriteChanges before querying. Please go through the MergeOptions explained in msdn to get a clear idea.
public List<vcData> GetTableData()
{
var currentMergeOption = _entities.vcData.MergeOption;
_entities.vcData.MergeOption = MergeOption.OverwriteChanges;
var result = (from td in _entities.vcData
where td.SiteID == "MySite"
select td).ToList();
//revert the change
_entities.vcData.MergeOption = currentMergeOption;
return result;
}

Categories

Resources