Diskuze: Entity Framework Code First a relace mezi tabulkami
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
Zobrazeno 13 zpráv z 13.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Máš to správně, myslím.
Kolekce se označují jako virtuální, aby se umožnil lazy-loading, ale
teoreticky není potřeba.
Hmm a jak teď vytvořím novou instanci Person s Kalendarem, protože když to zkouším, tak mi to nejde. A mám něco dávat do vlastností PersonId a Person? Nebo se to udělá automaticky?
using (var db = new PersonContext())
{
db.Persons.Add(new Person()
{
Jmeno = "Pavel",
Prijmeni = "Novak",
Vek = 20,
Kalendar = new Kalendar()
{
Udalost = "Schuzka",
Zprava = "Nejaka zprava",
}
});
}
Nooo.neukládáš to, musíš dát
db.SaveChanges();
No to sice taky, ale ještě předtím mi to začervení celý řádek, kde
se snažím vytvořit Kalendar a píše mi to:
"Cannot implicitly convert type 'DbModels.Models.Kalendar' to
'System.Collections.Generic.ICollection<DbModels.Models.Kalendar>'.
An explicit conversion exists (are you missing a cast?)"
Protože ty Kalendar je kolekce, ale ty se tam snažíš nacpat objekt. Měl bys změnit pojmenování.
using (var db = new PersonContext())
{
Person p=new Person()
{
Jmeno = "Pavel",
Prijmeni = "Novak",
Vek = 20,
Kalendar = new List<Kalendar>();
};
p.Kalendar.Add(new Kalendar()
{
Udalost = "Schuzka",
Zprava = "Nejaka zprava",
});
db.Persons.Add(p);
}
Vyřešil jsem to takto, a teď ještě jak ty data načíst zpět z databáze.
using (var db = new PersonContext())
{
db.Persons.Add(new Person()
{
Jmeno = "Pavel",
Prijmeni = "Novak",
Vek = 20,
Kalendar = new Collection<Kalendar>()
{
new Kalendar()
{
Udalost = "Schůzka",
Zprava = "V parku na náměstí",
Datum = "21.05.2016 12:00",
}
}
});
db.SaveChanges();
}
Třeba takto
using (var db = new PersonContext())
{
List<Person> people=db.Persons.ToList();
}
Jo a ještě něco, když máš Id nějaké třídy, tak se nepoužívá
[Key]
public int MojeTridaId ...
ale
[Key]
public int Id ...
Je to sice jen konvence, ale přecijen to je dobré.
Ještě se pokouším udělat si servisní třídu na načítání dat (mělo by se jednat o DTO, pokud jsem ten koncept pochopil správně)
public class DataService : DataServiceBase
{
public IEnumerable<Person> GetPersons()
{
using (var db = CreateDataContext())
{
return db.Persons.Select(s => new Person()
{
Id = s.Id,
FirstName = s.FirstName,
LastName = s.LastName,
Address = s.Address
}).ToList();
}
}
a pak ve ViewModelu
private ObservableCollection<Person> personObs = new ObservableCollection<Person>();
public ObservableCollection<Person> PersonObs
{
get { return personObs; }
set { personObs = value; NotifyOfPropertyChange(() => PersonObs); }
}
DataService ds = new DataService();
protected override void OnInitialize()
{
PersonObs.Clear();
foreach (var item in ds.GetPersons())
{
personObs.Add(item);
}
}
Dostanu ale následující chybu
Additional information: The entity or complex type
'WPF_DatabaseApplication.Context.Person' cannot be constructed in a LINQ to
Entities query.
Pro jistotu ještě přidám modely (vztah mezi modely by měl být 1 ku 1)
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual Address Address { get; set; }
}
a
public class Address
{
[Key, ForeignKey("Person")]
public int PersonId { get; set; }
public string Street { get; set; }
public string City { get; set; }
public virtual Person Person { get; set; }
}
To totiž nejde, entita reprezentuje řádek v tabulce a ne objekt sám o
sobě a to by rozbilo spoustu věcí.
Podívej se sem: http://stackoverflow.com/…tities-query
1. odkaz z Googlu btw
Ten odkaz jsem našel, ale nebyl jsem z něho právě moc chytrý. Proto se ptám i tady. Jak se to tedy řeší, když chci ty data z databáze dostat?
třeba takto:
var db = new PersonContext();
var osoba = db.Persons.FirstOrDefault();
to ti vytáhne první osobu z "tabulky" Persons...Pokud tam žádná není,
vrátí ti to null
A ten virtual tam je proto, aby jsi mohl přistoupit i k dalšímu objektu, tedy
v tomhle případě
var prvniKalendar= osoba.Kalendar.FirstOrDefault();
Pokud je osoba null, tak to žuchne.
ještě jedno upozornění: když máš kolekci tak jí nazývej množně, tedy Kalendare, takle se ti to akorát zamotá...
Ahoj, mám takový dojem, že to nebude to, na co se ptal.
Pro Milan:
Entity by ti nikdy neměly "probublávat" do uživatelského rozhraní. Je pro
to lepší využít právě DTO, na které se ptáš. Ty modely Person a Address
jsou v podstatě jen jakési šablony tabulek pro databázi (jak už uvedl
czubehead) a nic složitějšího, bys s nimi neměl dělat.
Pokud chceš mít nějakou třídu, která ti bude obsluhovat DAL (Data Access Layer), pak si vytvoř v projektu novou složku a tu nazvi například "DTO" a zde si založ třídu "PersonDTO" a "AddressDTO". Obě tyto třídy budou obsahovat jen ty property, které chceš ze svého modelu dostat. Takže např.:
public class AddressDTO
{
public string Street { get; set; }
public string City { get; set; }
}
public class PersonDTO
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
A pak následně vé tvé třídě DataService, bude metoda pro získání dat vypadat nějak takto:
public IEnumerable<PersonDTO> GetPersons()
{
using (var db = CreateDataContext())
{
return (from s in db.Persons
select new PersonDTO
{
Id = s.Id,
FirstName = s.FirstName,
LastName = s.LastName
}).ToList();
}
}
public IEnumerable<AddressDTO> GetAddress(int id)
{
using (var db = CreateDataContext())
{
return (from s in db.Addresses where s.PersonId == id
select new AddressDTO
{
City = s.City,
Street = s.Street
}).ToList();
}
}
Samozřejmě nezapomeň, že pokud to budeš ukládat do nějakého listu a zobrazovat třeba ve WPF DataGridu, tak ten list musí být rovněž datového typu PersonDTO a AddressDTO. Doufám, že to je to, co jsi chtěl vědět a pokud jsem zde napsal nějakou hloupost, tak prosím někoho fundovanějšího o opravu.
Zobrazeno 13 zpráv z 13.