PDA

View Full Version : سوال: مشکل با ایجاد سطر جدید در Entity Framework Code first



m2011kh
جمعه 26 خرداد 1396, 18:53 عصر
سلام و خسته نباشید دوستان عزیز.

بنده در حال نوشتن یه برنامه کوچیک هستم. شرح مشکل به این صورت هست که من یه تابع استاتیک دارم که هنگام شروع برنامه چک میکنه که آیا جدول هایی که نباید خالی باشن خالی هستن یا نه. و اگه هستن سطر های پیشفرض رو به جدول اضاقه میکنه. بانک اطلاعاتی بوسیله Code first migrations ساخته شده.

این کد تابع :

class DatabaseAufpasser {


public static void DatabaseChecker()
{
using (var _db = new DataContext())
{
if (!_db.KasseGemeinsam.Any())
{
_db.KasseGemeinsam.Add(new Models.Data.KasseGemeinsamModel() { Jahr = DateTime.Now.Year.ToString(), Monat = MonatenVertauchen.ZahlZuMonaten(Convert.ToInt32(Da teTime.Now.Month)), Haushalt = 0, Hygine = 0, Mobel = 0, Nahrung = 0, Schreibware = 0, Sonstiges = 0 });
_db.SaveChanges();
}


if (!_db.KassePrivat.Any())
{
_db.KassePrivat.Add(new Models.Data.KassePrivatModel() { Jahr = DateTime.Now.Year.ToString(), Monat = MonatenVertauchen.ZahlZuMonaten(Convert.ToInt32(Da teTime.Now.Month)), UserID = UserIdentity.UserID, Fahrkosten = 0, Hygine = 0, Mobel = 0, Nahrung = 0, Schreibware = 0, Sonstiges = 0 });
_db.SaveChanges();
}


if (!_db.GemeinsamKasse.Any())
{
_db.GemeinsamKasse.Add(new Models.Data.GemeinsamKasse() { Betrag = 0 });
_db.SaveChanges();
}


if (!_db.PrivatKasse.Any())
{
List<int> userIDs = new List<int>();
foreach (var item in _db.UsersTbl)
{
userIDs.Add(item.ID);
}
using (var _db2 = new DataContext())
{
foreach (var item in userIDs)
{
_db2.PrivatKasse.Add(new Models.Data.PrivatKasse() { BenutzerID = item, Betrag = 0 });


}
_db2.SaveChanges();
}




}



}
}
}

داخل کد میبینید که این تابع روی چهار جدول این تست رو انجام میده. روی سه جدول دیگر کاملا درست کار میکنه با اینکه خصوصیات ID همه چهار جدول رقیقا مثل هم هست ولی وقتی که روی کار در جدول آخر میرسه این خطا رو برمیگردونه:
145515

متن ارور:

System.Data.Entity.Infrastructure.DbUpdateExceptio n ist aufgetreten. HResult=0x80131501
Nachricht = An error occurred while updating the entries. See the inner exception for details.
Quelle = EntityFramework
Stapelüberwachung:
bei System.Data.Entity.Internal.InternalContext.SaveCh anges()
bei System.Data.Entity.Internal.LazyInternalContext.Sa veChanges()
bei System.Data.Entity.DbContext.SaveChanges()
bei MoneyVerwaltung.DatabaseAufpasser.DatabaseChecker( ) in C:\Users\MMD\Documents\Visual Studio 2017\Projects\MoneyVerwaltung 1.0\MoneyVerwaltung\MoneyVerwaltung\DatabaseAufpas ser.cs: Zeile50
bei MoneyVerwaltung.frmHome..ctor() in C:\Users\MMD\Documents\Visual Studio 2017\Projects\MoneyVerwaltung 1.0\MoneyVerwaltung\MoneyVerwaltung\frmHome.cs: Zeile27
bei MoneyVerwaltung.frmAnmeldung.button1_Click(Object sender, EventArgs e) in C:\Users\MMD\Documents\Visual Studio 2017\Projects\MoneyVerwaltung 1.0\MoneyVerwaltung\MoneyVerwaltung\frmAnmeldung.c s: Zeile59
bei MoneyVerwaltung.frmAnmeldung.txtPassword_Keypress( Object sender, KeyPressEventArgs e) in C:\Users\MMD\Documents\Visual Studio 2017\Projects\MoneyVerwaltung 1.0\MoneyVerwaltung\MoneyVerwaltung\frmAnmeldung.c s: Zeile84
bei System.Windows.Forms.Control.OnKeyPress(KeyPressEv entArgs e)
bei System.Windows.Forms.Control.ProcessKeyEventArgs(M essage& m)
bei System.Windows.Forms.Control.ProcessKeyMessage(Mes sage& m)
bei System.Windows.Forms.Control.WmKeyChar(Message& m)
bei System.Windows.Forms.Control.WndProc(Message& m)
bei System.Windows.Forms.TextBoxBase.WndProc(Message& m)
bei System.Windows.Forms.TextBox.WndProc(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
bei System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message& m)
bei System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
bei System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
bei System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
bei System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason, ApplicationContext context)
bei System.Windows.Forms.Application.Run(Form mainForm)
bei MoneyVerwaltung.Program.Main() in C:\Users\MMD\Documents\Visual Studio 2017\Projects\MoneyVerwaltung 1.0\MoneyVerwaltung\MoneyVerwaltung\Program.cs: Zeile19


Innere Ausnahme 1:
UpdateException: An error occurred while updating the entries. See the inner exception for details.


Innere Ausnahme 2:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.PrivatKasses'. Cannot insert duplicate key in object 'dbo.PrivatKasses'. The duplicate key value is (0).
The statement has been terminated.



دوستان نظر یا راه حلی در مورد این مشکل دارید؟


موفق و سربلند باشید.

mr.sirwan
جمعه 26 خرداد 1396, 19:26 عصر
با سلام دوست عزیز ارورتون کاملا گویا هستش، میگه نمیشه چند سطر با کلید اصلی یکسان داخل اون جدول درج کرد، شما Id رو Autoincreament کنین با اتریبیوت DatabaseGenerated(DatabaseGeneratedOption.Identity ) که خودش مقدار بگیره


اینم اون قسمت از متن ارورتون که توضیح داده:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.PrivatKasses'. Cannot insert duplicate key in object 'dbo.PrivatKasses'. The duplicate key value is (0).
The statement has been terminated.

ژیار رحیمی
جمعه 26 خرداد 1396, 19:53 عصر
سلام . مشکل در جدول چهارم که بیان کردی شما UserId که برای جدول PK_dbo.PrivatKasses لازم هست مقدار دهی شود، مقدار دهی نکردی(برای رکورد اول UserId صفر و همچنین برای رکورد دوم هم صفر درج میشود) که حطای تکرار در کلید به شما میدهد. (خطای Cannot insert duplicate key )


Innere Ausnahme 2:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.PrivatKasses'. Cannot insert duplicate key in object 'dbo.PrivatKasses'. The duplicate key value is (0).
The statement has been terminated.

*** در کل روش شما برای مقدار دهی اولیه به جداول مناسب نمیباشد. بهتره از راحل خود EF برای seed کردن در دیتابیس استفاده کنی که روشی کارامد هست.
http://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx
https://www.tutorialspoint.com/entity_framework/entity_framework_seed_database.htm

m2011kh
جمعه 26 خرداد 1396, 20:43 عصر
تغییر دادم ولی باز هم همون exeption رو دریافت کردم.

m2011kh
جمعه 26 خرداد 1396, 20:50 عصر
سلام . مشکل در جدول چهارم که بیان کردی شما UserId که برای جدول PK_dbo.PrivatKasses لازم هست مقدار دهی شود، مقدار دهی نکردی(برای رکورد اول UserId صفر و همچنین برای رکورد دوم هم صفر درج میشود) که حطای تکرار در کلید به شما میدهد. (خطای Cannot insert duplicate key )

*** در کل روش شما برای مقدار دهی اولیه به جداول مناسب نمیباشد. بهتره از راحل خود EF برای seed کردن در دیتابیس استفاده کنی که روشی کارامد هست.
http://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx
https://www.tutorialspoint.com/entity_framework/entity_framework_seed_database.htm


بله کاملا صحیح عرض میکنید. دو مقدار یکسان برای ID در نظر گرفته میشه. روش مقدار دهی اولیه رو هم تغییر خواهم داد. ولی فرض کنیم که در یک جایی دیگه ی برنامه من به همین روش داخل حلقه چند تا سطر جدید اضافه کنم. چکار کنم که یک مقدار برای دو ID در نظر گرفته نشه؟ من راه حلی به ذهنم نمیرسه.

موفق و سربلند باشید.

ژیار رحیمی
جمعه 26 خرداد 1396, 23:52 عصر
شما جایی که لازمه رکورد اضافه کنی باید به تعداد رکوردهای موجود در جدول UsersTbl رکورد در جدول PrivatKasses درج کنی. شما دو کلاس مربوط به دو جدول رو بزار تا راهنمایی بیشتر صورت گیرد.

foreach (var item in _db.UsersTbl.ToList())
{
_db.PrivatKasse.Add(new Models.Data.PrivatKasse()
{
BenutzerID = item.ID,//must be assign the Id of item record
Betrag = 0 ,
UserId=item.ID//must be assign the Id of item record
});
}

m2011kh
شنبه 27 خرداد 1396, 01:26 صبح
شما جایی که لازمه رکورد اضافه کنی باید به تعداد رکوردهای موجود در جدول UsersTbl رکورد در جدول PrivatKasses درج کنی. شما دو کلاس مربوط به دو جدول رو بزار تا راهنمایی بیشتر صورت گیرد.

foreach (var item in _db.UsersTbl.ToList())
{
_db.PrivatKasse.Add(new Models.Data.PrivatKasse()
{
BenutzerID = item.ID,//must be assign the Id of item record
Betrag = 0 ,
UserId=item.ID//must be assign the Id of item record
});
}



در واقع یک جدول برای کاربر هاست که از روی اسمش مشخص هست و قراره به اضای هر کاربر یک سطر در جدول دیگری ساخته شود.

Model جدول ها:

class PrivatKasse {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity )]
public int ID { get; set; }
public decimal Betrag { get; set; }
public int BenutzerID { get; set; }


}

class UserModel {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }
[MaxLength(50)]
public string Username { get; set; }

[MaxLength(25), MinLength(8)]
public string Password { get; set; }
[MaxLength(50)]
public string Vorname { get; set; }
[MaxLength(50)]
public string Nachname { get; set; }
[MaxLength(50)]
[EmailAddress]
public string Email { get; set; }
[MaxLength(50)]
public string Tel { get; set; }
public DateTime Geburtstag { get; set; }
}

و کلاس Context :

class DataContext : DbContext {
public DbSet<UserModel> UsersTbl { get; set; }
public DbSet<ZahlungGModel> ZahlungGTbl { get; set; }
public DbSet<ZahlungPrivatModel> ZahlungPrivateTbl { get; set; }
public DbSet<KasseGemeinsamModel> KasseGemeinsam { get; set; }
public DbSet<KassePrivatModel> KassePrivat { get; set; }
public DbSet<PrivatKasse> PrivatKasse { get; set; }
public DbSet<GemeinsamKasse> GemeinsamKasse { get; set; }
public DbSet<EinkommenModel> Einkommentbl { get; set; }
public DbSet<SchuldenModel> Schulden { get; set; }


}

ژیار رحیمی
شنبه 27 خرداد 1396, 08:37 صبح
ارتباط بین User و PrivatKasse یک ارتباط یک به یک هست با این شرط که امکان درج User بدون PrivatKasse وجود دارد ولی امکان درج رکورد PrivatKasse بدون User امکان پذیر نمی باشد.(شرط لحاظ شده در بخش Fluent API )
1- در نام گذاری پراپرتی ها از زبانی به غیر از زبان انگلیسی استفاده نکن (جهت خوانایی برای دیگر برنامه نویس ها)
2- نام Entity ها بصورت مفرد و نام آن در تعریف DbSet بصورت جمع باشد (یک نوع استاندارد هست)

public class PrivatKasse {
[ForeignKey("User")]
public int UserId { get; set; }
public decimal Betrag { get; set; }
public virtual User User { get; set; }


}


public class User {
public int Id { get; set; }
[MaxLength(50)]
public string Username { get; set; }
//...
//...
public virtual PrivatKasse PrivatKasse { get; set; }
}


public class DataContext : DbContext {


public DataContext(): base("DataContextConnectionString")
{
Database.SetInitializer(new DataContextInitializer());
}


public DbSet<User> Users { get; set; }
public DbSet<PrivatKasse> PrivatKasses { get; set; }
//...
//...


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOptional(s => s.PrivatKasse) // Mark PrivatKasse property optional in User entity
.WithRequired(a => a.User); // mark User property as required in PrivatKasse entity. Cannot save PrivatKasse without User


}

}


public class DataContextInitializer : CreateDatabaseIfNotExists<DataContext>
{
protected override void Seed(DataContext context)
{

var lstUsers = new List<User>();


lstUsers.Add(new User() { Username = "user1", /* .... */ });
lstUsers.Add(new User() { Username = "user2", /* .... */ });
lstUsers.Add(new User() { Username = "user3", /* .... */ });


foreach (var user in lstUsers)
{
user.PrivatKasse = new PrivatKasse(){Betrag = 0};
context.Users.Add(user);
}


/*
context.Users.Add(new User()
{
Username = "user1",
//...
//...
PrivatKasse = new PrivatKasse(){Betrag = 0}
});
context.Users.Add(new User()
{
Username = "user2",
//...
//...
PrivatKasse = new PrivatKasse(){Betrag = 0}
});
context.Users.Add(new User()
{
Username = "user3",
//...
//...
PrivatKasse = new PrivatKasse(){Betrag = 0}
});
*/


//context.SaveChanges();
base.Seed(context);
}
}