I need to store an instance of an complex datatype into a relational database.
Is there a way to do this without moddeling the database structure first, like it is done in ado.net? The database (or table) structure should be created from the class structure. The class has some properties like ints, strings or bools but could also have more complex ones.
I am grateful for every helping advice...
I want to do this in c#...
Update:
Thank you for your replys. I tried "code first" of EF 4 (Thank you very much Ramesh) and got my objects into the database. But now I am having a problem to get the data out of the db back to the instance of an object. My classes look like that:
class Foo {
public int id { get; set; }
public string Woot { get; set; }
}
class Bar {
public int id { get; set; }
public string name { get; set; }
public ICollection<Foo> FooList { get; set; }
}
So, as I said i can create instances of these classes and write them to the db. But when I try to create new instances from the db data, just the int and the string of the "Bar"type is recovered but the Collection of Foos is emtpy. My db context looks like this:
class DBstructure: DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
}
any Idea?
Yes thats possible, you have to use Entity framework 4 for this. the approach is called "Code First".
you can read lot about this here in ScottGu's post Code-First Development with Entity Framework 4
The best is to use an ORM tool that can build the database for you from your domain model (classes).
Look at NHibernate, Entity Framework to mention a few.
I got what I wanted using the Entity Framework 4 with "code first". To write Objects from the classes I posted above, into the databse you just have to create the objects regulary:
Foo foo = new Foo();
foo.Woot = "foo1";
Foo foo2 = new Foo();
foo2.Woot = "foo2";
Bar bar = new Bar();
bar.name = "bar1";
bar.Whee = new List<Foo>();
bar.Whee.Add(foo);
bar.Whee.Add(foo2);
Then create the DbContext object, add the other objects to this context and call saveChanges() method:
DBstructure dbconn = new DBstructure();
dbconn.Database.Connection.ConnectionString = connectionString //depends on your DB
dbconn.Bars.Add(bar);
dbconn.Database.Connection.Open();
dbconn.SaveChanges();
dbconn.Database.Connection.Close();
That creates the new database with the tables "Foos" and "Bars" and another link table to manage the relations between the entitys.
Creating objects from the database information is also quite easy. Just connect to the database via the DbContext as it was done above. Create your objects and set them to the db data:
DBstructure dbconn = new DBstructure();
dbconn.Database.Connection.ConnectionString = connString;
dbconn.Foos.ToList(); //seems that you have to do that
dbconn.Bars.ToList<Bar>();
Bar barFromDB = new Bar();
barFromDB = dbconn.Bars.First<Bar>();
That works fine in my application. Sorry for the strange class and variable names. I just copied the code from my test application. Hope that helps someone...
Grüßung Jucker!
Related
Objective:
Use EF to enter in data from a POST request from an API. The POST request will contain an "ID", that will map the connection string to an enum, which will have the same name connection string name as it has in the Web.config. Create the "base" context object and add the object to the appropriate table.
Note:
I know I can do this using SqlCommand, but I wanted to take a crack at it using entity framework instead, but I hit a wall.
I've used EF for years, but I wanted to make this POST method as global as I can get it. This API will accept numerous requests from numerous different web sites, but all will use the same model. Each websites POST will go into a different database (that's how they are requesting it).
The problem that I foresee is, each "entity" knows what tables it contains. So when one types context.TABLE.Add(object), EF understands that you want to put this "Car" object in the "Car" table (obviously).
Can this be done using a "global" entity???
public class DbConnectionNames
{
public enum DbConnectionStringNames
{
SocHopeHcpEntities = 1, // "1" is passed into the POST to map
XXXXEntities = 2,
......
}
}
<add name="SocHopeHcpEntities" connectionString=".........." />
<add name="XXXXEntities" connectionString=".........." />
.....
var professional = new Professional
{
....
....
};
string connStringContext = Enum.GetName(typeof(DbConnectionNames.DbConnectionStringNames), model.FormId).ToString();
string connectionString = ConfigurationManager.ConnectionStrings[connStringContext].ConnectionString;
using (var context = new ObjectContext(connectionString))
{
context.Professionals.Add(professional); // obviously this doesn't work
context.SaveChanges();
}
EDIT:
My EF is NOT using POCO, but is already based off a DB to begin with. There could be XX number of different databases, all holding the same similar table. I already have a YYYEntities.Context.cs file auto-generated that inherits from DbContext:
public partial class SocHopeHcpEntities : DbContext
{
public SocHopeHcpEntities()
: base("name=SocHopeHcpEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<AreasOfWork> AreasOfWorks { get; set; }
public virtual DbSet<Professional> Professionals { get; set; }
}
You still need a context that understands what a Professional is. For example:
public class ProfessionalContext : DbContext
{
public ProfessionalContext(string connectionString)
: base(connectionString)
{
//This line is optional but it prevents initialising the database
//every time you connect to a new database
Database.SetInitializer<ProfessionalContext>(null);
}
public DbSet<Professional> Professionals { get; set; }
}
And use it like this:
using (var context = new ProfessionalContext(connectionString))
{
context.Professionals.Add(professional);
context.SaveChanges();
}
DavidG's answer showed you how to pass a connection string to a strongly typed context that knows the entity types you are dealing with. That context inherits from DbContext which you can use directly as illustrated below.
It is worth noting the generic way that does not involve a context 'object' that is specific to your database.
For example see how ObjectContext is used here:
System.Data.Objects.ObjectContext oc = new System.Data.Objects.ObjectContext("connection string");
oc.AddObject("ProfessionalsTable", professional);
Another example is using DbContext:
System.Data.Entity.DbContext dbc = new DbContext("");
dbc.Set(typeof(Professional)).Add(professional);
The generic approach is better if you also do not know which table you want to insert to, so you can also make the object that you want to insert dynamic.
Being new to ASP .NET I've been researching on entity modeling approaches and it seems ORM using Entity Framework following Code First is the best approach for me.
By following this tutorial, I have gotten the impression that, for each entity, you need to create a connectionstring (correct me if I'm wrong) and this fact confuses me when it comes to relational data, as, per this example, the database itself seems to cover just one entity. So how is relational data handled in the EF.
PS: For unification purpose, please use entities Movies, Customers and the relational table named under the proper naming conventions.
You create a connection string per DbContext. Here is the class that defines the DBContext:
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
To add more tables to this context, add more lines like this (for examples, public DbSet<Customer> Customers { get; set; }.
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
public DbSet<Ticket> Tickets { get; set; }
}
Accessing these from a context:
public class TicketController {
private MovieDBContext db = new MovieDBContext ();
public ActionResult Index(int movieId) {
var listOfTickets = db.Tickets.Where(t=>t.MovieId == movieId).ToList();
var parentMovie = db.Movie.Where(m=>m.Id == movieId).Single();
...
}
}
Connection String: Contains initialization information that is passed as a parameter from a data provider to a data source.
You need a new connection string each time you are connecting to something different (You can have two different DBContexts using the same ConnectionString), in this tutorial although the Data Source of both connection strings is the same, the AttachDbFileName is different.
When each DbContext is initialized, it will use one of those connection strings. In this tutorial, the first connection string (Default Connection) is used for membership (user accounts and such) and the other connection string is used for your MovieDBContext, and will contain Movies and other things as you progress in the tutorial.
It's also possible to have them both in the same database.
I have an existing database with two tables MailServers and MailDomains in it. MailDomains has the foreign key column MailServerId pointing to the Id primary key column in MailServers. So we have a one-to-many-relationship here.
I followed this article and created my Entity Framework POCOs via the "Code first from database" model in the Entity Data Model Wizard. This produced the following two C# classes:
public partial class MailServer
{
public MailServer()
{
MailDomains = new HashSet<MailDomain>();
}
public int Id { get; set; }
public virtual ICollection<MailDomain> MailDomains { get; set; }
}
public partial class MailDomain
{
public MailDomain()
{
}
public int Id { get; set; }
public string DomainName { get; set; }
public int MailServerId { get; set; }
public virtual MailServer MailServer { get; set; }
}
Now my question is whether there is any difference between the following two approaches of creating and inserting new objects to the database.
Approach (A): Adding new child to the parent's list:
var mailServer = new MailServer();
var mailDomain = new MailDomain() {
DomainName = "foobar.net",
};
mailServer.MailDomains.Add(mailDomain);
using(var context = new MyContext){
context.MailServers.Add(mailServer);
context.SaveChanges();
}
Approach (B): Setting the child's navigation property to the parent:
var mailServer = new MailServer();
var mailDomain = new MailDomain() {
DomainName = "foobar.net",
MailServer = mailServer,
};
using(var context = new MyContext){
context.MailDomains.Add(mailDomain);
context.SaveChanges();
}
I also assume that in approach (A) the new MailDomain instance is automatically added to the collection context.MailDomains while in approach (B) the new MailServer instance is automatically added to the collection context.MailServers. Is that correct or do I have to do that manually?
So again, my question is: are the two approaches interchangeable?
It just confuses me that in the database there is only one property/column to set (namely the foreign key in MailDomains) while in the C# code there are two properties (one in each class) that could be modified.
Yes, the two approaches are interchangeable. This allows you to create and save your object graph to the database from either the perspective of the MailServer or the MailDomain.
If you do code-first, you have the option of removing the properties and mappings if they're not needed.
I also assume that in approach (A) the new MailDomain instance is
automatically added to context.MailDomains while in approach (B) the
new MailServer instance is automatically added to context.MailServers.
Is that correct or do I have to do that manually?
It depends what you mean by "added to the context". If you mean: does it automatically get saved to the database when you persist, the answer is yes. One of the big benefits to using an ORM like EF is that it handles saving a full object graph automatically (and syncing PK/FK relations, etc.).
If you mean: will the entity be available via the context before saving, I don't think so (I'm not 100% sure).
I am having some problem about how to work with an entity say an EF entity and a surrogate type, which will be bound to the UI.
Suppose that I have following classes
// Db Entity
public class Car
{
public virtual int Id { get; set; }
public string ChassisNumber { get; set; }
public virtual string Brand { get; set; }
public virtual string Name { get; set; }
}
// Surrogate type that reflects some properties of Car entity
// This class will be bound to UI
public class SurrogateCar
{
public string Brand { get; set; }
public string Name { get; set; }
}
Now I will be getting List<Car> from db and want to create a List<SurrogateCar> that represents my entities. I can do this easily in many ways, one of them like this:
List<Car> cars = CarTable.GetMyCars(); // Just a dummy method, suppose it returns all entities from Db.
List<SurrogateCar> surrogates = new List<SurrogateCar>();
foreach (var car in cars)
{
surrogates.Add(new SurrogateCar { Brand = car.Brand, Name = car.Name });
}
or I can write a custom cast method. But what I worry about is the performance. This method will be called frequently, so creating a list and populating it one by one seems a potential problem to me.
Do you have any better ways to do this, or is it okay to use it like this?
Thanks.
If you have a web service, and that service is always going to return the SurrogateCar class, then you can write your entity query to return the class you want rather than getting the class you don't want:
var cars = from c in context.Cars where {your condition}
select new SurrogateCar
{
Brand=c.Brand,
Name=c.Name
};
If, on the other hand you need the list of cars all the time, then as Roger pointed out AutoMapper is great! You just call
CreateMap<Car, SurrogateCar>
then you just use Automapper to populate your new list:
surrogates.AddRange(Map<IEnumberable<Car>, IEnumerable<SurrogateCar>>(cars));
Don't worry about the performance until you've really measured that's your bottleneck! Most probably these mappings between different types aren't that slow.
There are tools out there, eg AutoMapper
http://automapper.org/
It's main purpose isn't performance though, but to potentially makes you write easier and less code.
I believe what you are really looking for is AutoMapper, it allows for seamless, easy code written around this situation. I would not worry too much about the performance unless you need to worry about it.
Here is a SO about mapping lists using automapper, also
I am using RIA Service in our Silverlight application. Database entities are not directly exposed to a client but I have a set of POCO classes for it. Then in CRUD methods for these POCO classes they are converted to database entities and saved to database.
The problem arises on the server side when client creates 2 new POCO entities which are related. Insert method is called on the server for each POCO entity separately and I may create corresponding new database entities there and add them to object context. But I see no way to add relation between these created database entities. Is there a solution for that?
For example, I have these 2 POCO entities (simplified):
[DataContract(IsReference = true)]
public partial class Process
{
[DataMember]
[Key]
public string Name
{
get; set;
}
[DataMember]
public long StepId
{
get; set;
}
[DataMember]
[Association("StepProcess", "StepId", "Id", IsForeignKey=true)]
public Step Step
{
get; set;
}
}
[DataContract(IsReference = true)]
public partial class Step
{
[DataMember]
[Key]
public long Id
{
get; set;
}
[DataMember]
public string Name
{
get; set;
}
}
And I have these 2 Insert methods in my domain service class:
public void InsertProcess(Process process)
{
var dbProcess = new DBProcess();
dbProcess.Name = process.Name;
//dbProcess.StepId = process.StepId; Cannot do that!
this.ObjectContext.AddToDBProcess(dbProcess);
}
public void InsertStep(Step step)
{
var dbStep = new DBStep();
dbStep.Name = step.Name;
this.ObjectContext.AddToDBSteps(dbStep);
this.ChangeSet.Associate<Step, DBStep>
(step, dbStep, (dto, entity) =>
{
dto.Id = entity.Id;
});
}
Client adds a new Process, then creates and adds a new Step to it and then calls SubmitChanges(). Process.StepId is not filled with a correct value as there is no correct Step.Id for the newly created step yet, so I cannot just copy this value to database entity.
So the question is how to recreate relations between newly created database entities the same as they are in newly created DTOs?
I know about Composition attribute but it is not suitable for us. Both Process and Step are independent entities (i.e. steps may exist without a process).
There are two ways to solve this:
Have each call return the primary key for the item after it is created, then you can store the resulting PKey in the other POCO to call the second service.
Create a Service method that takes both POCOs as parameters and does the work of relating them for you.
Thanks, although both these suggestions are valid but they are also applicable only for simple and small object hierarchies, not my case. I end up using approach similar to this. I.e. I have a POCO to database objects map. If both Process and Step are new, in InsertProcess method process.Step navigation property is filled with this new step (otherwise StepId can be used as it referenced to existing step). So if this process.Step is in the map I just fill corresponding navigation property in DBProcess, otherwise I create new instance of DBStep, put it to the map and then set it to DBProcess.Step navigation property. This new empty DBStep will be filled in InsertStep method later.