C# LINQ rekord eltávolítása foreign constraint jelenléte esetén?
Van egy receptalkalmazás, amiből törölni kellene tudni recepteket. Egy recept úgy áll össze, hogy fogásID idegen kulcsként, mennyiség, mennyiség mértékegységID idegen kulcsként és nyersanyagID idegen kulcsként. Ha szeretnék törölni egy receptet, azt hogy tudom megtenni. Arra gondoltam, hogy végigiterálok az összes olyan rekordon, ami a törlendő fogásID-kat tartalmazza, majd minden értéket null-ra állítok (adatbázisban felvehet minden null értéket). A problémám, hogy mégsem hagyja null-ra állítani kódból, mivel az Anonymous Type read-only. Hogy tudnám ezt valahogy megoldani? A kód, amire jutottam:
Fogasok fogás = (Fogasok)újÉtelekListBox.SelectedItem;
var tf = (from r in db.Receptek
join f in db.Fogasok on r.FogasID equals f.FogasID
join me in db.MennyisegEgysegek on r.MennyisegEgysegID equals me.MennyisegEgysegID
join ny in db.Alapanyagok on r.NyersanyagID equals ny.AlapanyagID
where f.FogasID == fogás.FogasID
select new { me.MennyisegEgysegID, r.Mennyiseg, ny.AlapanyagID }).ToList();
foreach (var item in tf)
{
item.AlapanyagID = null;
item.Mennyiseg = null;
item.MennyisegEgysegID = null;
}
db.Fogasok.DeleteObject(fogás);
db.SaveChanges();
Szia!
Kicsit berozsdásodott már a C# tudásom (ha volt egyáltalán), ezért inkább logikailag szeretnék segíteni. (Meg érdekel is a probléma.)
A receptek és a fogások milyen kapcsolatban vannak? (Hogy jön ide az idegen kulcs?) <- ez nekem nem világos a leírásodból...
Így épül fel az adatbázis:
Fogások tábla: id (pk), fogás neve, leírás
Mértékegységek tábla: id (pk), mértékegység neve
Alapanyagok tábla: id (pk), alapanyag neve
Receptek tábla: id (pk), fogásID (idegen kulcs), mennyiség, mértékegységID (idegen kulcs), alapanyagID (idegen kulcs)
A receptek tábla tehát egy saját id-ből és float típusú mennyiségből, illetve 3 idegen kulcsból áll.
A jelenlegi formájában csak úgy tudod törölni a fogást, ha törlöd a rá hivatkozó recepteket is. De valószínűleg nem ez az, amit akarsz, hiszen egy receptnek önmagában is van értelme.
Ebből már sejthető, hogy itt egy DB tervezési hiba van. Te azt feltételezted, hogy egy receptre csak egyetlen egy fogás hivatkozhat, ez 1:N kapcsolat lenne, de ez nyilván nem így van, egy recept több fogásnak is része lehet, és az is egyértelmű, hogy egy fogás több receptből áll.
Szóval ez N:M kapcsolat, amit relációs DB-k esetén kapcsolótáblával szokás megoldani.
Azaz, a recept-ből kiveszi a fogás FK-t, és csinálsz egy olyan táblát, hogy:
ReceptFogasRelation, ebben két FK lesz, a Recept ID, és Fogás ID, és együtt alkotják a PK-t.
Természetesen ezzel a megoldással sem úszod meg, hogy a fogás törlése esetén a relation táblából is törölj, viszont egy fogás törlése nem vonja maga után a rá hivatkozó receptek törlését, így elkerülheted a nem kívánt adatvesztést.
Egy kis elmélet a relációs DB-kről, főleg a normálformák lesznek számodra érdekesek:
"Azt nem tudom, hogy hogyan tudom törölni a recepteket anélkül, hogy azzal alapanyagból vagy mértékegységből is törölnék."
Mivel sem az alapanyag, sem a mértékegység nem tartalmaz FK-t a receptre, ezért a recept tábla rekord-jai simán törölhetők.
Tehát, a törlési algoritmus a következő, ha fogást akarsz törölni:
1. Végigiterálsz a recepteken, amik hivatkoznak rá, és törlöd őket:
var receptek = (from r in db.Receptek where r.FogasID = [a fogás ID-ja] select r);
db.Fogasok.DeleteAllOnSubmit(receptek);
db.SubmitChanges();
2. Törlöd a fogást
db.Fogasok.DeleteonSubmit([a fogás, amit törölni akarsz]);
db.SubmitChanges();
És persze nem árt az egészet egy transationscope-ba tenni:
using (TransactionScope scope = new TransactionScope())
{
var receptek = (from r in db.Receptek where r.FogasID = [a fogás ID-ja] select r);
db.Fogasok.DeleteAllOnSubmit(receptek);
db.SubmitChanges();
db.Fogasok.DeleteonSubmit([a fogás, amit törölni akarsz]);
db.SubmitChanges();
scope.Complete();
}
Na, most eljutottam oda, hogy egyesével ki tudom törölni a hozzávalókat. Miután az összeset eltávolítottam, törölném magát a fogást, ezt a hibaüzenetet kapom:
"A művelet végrehajtása sikertelen: A kapcsolat módosítása sikertelen, mert a külső kulcs egy vagy több tulajdonsága nem nullázható. Egy kapcsolat módosításakor a rendszer null értékre állítja be a külső kulcs megfelelő tulajdonságát. Ha a külső kulcs nem támogatja a null értékeket, akkor új kapcsolatot kell definiálni, másik, null értéktől eltérő értéket kell rendelni a külső kulcs tulajdonságához, vagy törölni kell a nem kapcsolódó objektumot."
A kód így néz ki most:
using (receptadatbazisEntities rae = new receptadatbazisEntities())
{
Receptek recept = ((ObjectQuery<Receptek>)rae.Receptek)
.Include("Fogasok")
.Include("Alapanyagok")
.Include("MennyisegEgysegek")
.FirstOrDefault(i => i.FogasID == fogás.FogasID);
rae.Receptek.DeleteObject(recept);
rae.SaveChanges();
}
Kapcsolódó kérdések:
Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!