malaikuangren

What is the purpose or drive to build thing like (xxx),How can it achieve the original goal of design?
Code First Reference In Entity Framework

Convention

Core to Code First is the concept of conventions—default rules that Code First will use to build a model based on your classes. For example, Entity Framework requires that a class that it will manage has a key property. Code First has a convention that if it finds a property named Id or a property with the combined name of the type name and Id (e.g., PatientId), that property will be automatically configured as the key. If it can’t find a property that matches this convention, it will throw an exception at runtime telling you that there is no key.

only defining the domain classes have nothing to do with the Entity Framework.They have no knowledge of it. That’s the beauty of working with Code First. You get
to use your own classes. This is especially beneficial if you have existing domain classes from another project. To use Code First, you start by defining a class that inherits from DbContext. One of the roles of this class, which we’ll refer to as a context, is to let Code First know about the classes that make up your model. That’s how Entity Framework will be aware of them and be able to keep track of them. This is done by exposing the domain classes through another new class introduced along with DbContext—the DbSet. Just as DbCon text is a simpler wrapper around the ObjectContext, DbSet is a wrapper around Entity Framework 4’s ObjectSet, which simplifies coding tasks for which we normally use the ObjectSet.

If you have worked with Entity Framework, you are familiar with the model that is expressed in an EDMX file that you work with in a visual designer. You may also be
aware of the fact that the EDMX file is in fact an XML file, but the designer makes it much easier to work with. The XML used to describe the model has a very specific
schema and working with the raw XML would be mind-boggling without the designer. What is not as obvious in the designer is that the XML contains more than just the description of the conceptual model that is displayed in the designer. It also has a description of database schema that the classes map to and one last bit of XML that describes how to get from the classes and properties to the tables and columns in the database. The combination of the model XML, the database schema XML, and the mapping XML are referred to as metadata.

At runtime, the Entity Framework reads the XML that describes all three parts of the XML and creates an in-memory representation of the metadata. But the in-memory metadata is not the XML; it is strongly typed objects such as EntityType, EdmProperty, and AssociationType. Entity Framework interacts with this in-memory representation of the model and schema every time it needs to interact with the database. Because there is no XML file with Code First, it creates the in-memory metadata from what it can discover in your domain classes. This is where convention and configuration
come into play. Code First has a class called the DbModelBuilder. It is the DbModel Builder that reads the classes and builds the in-memory model to the best of its ability.
Since it is also building the portion of the metadata that represents the database schema, it is able to use that to create the database. If you add configurations to help the model builder determine what the model and database schema should look like, it will read those just after it inspects the classes and incorporate that information into its understanding of what the model and database schema should look like. Figure 1-4 shows how Entity Framework can build the in-memory model from code or from an XML file maintained through the designer. Once the in-memory model is created, Entity Framework doesn’t need to know how the model was created. It can use the in-memory model to determine what the database schema should look like, build queries to access data, translate the results of queries into your objects, and persist changes to those objects back to the database.

Convention and Configuration For Property Attribute

Configuring the Key with Data Annotations

[Key]
public Guid Identifier { get; set; }

Using HasKey to Configure a Key Property in the Fluent API

modelBuilder.Entity<Trip>().HasKey(t => t.Identifier)

If you are encapsulating the configurations within EntityTypeConfiguration classes, as

you learned about in Chapter 2, you begin with HasKey or this.HasKey

HasKey(t => t.Identifier)

Code First Convention and TimeStamp fields
By default, Code First does not recognize TimeStamp properties, so there is no conventional behavior. You must configure properties to get the behavior. Using Data Annotations to Configure TimeStamp Not just any property can be mapped to a timestamp database type. You must use a byte array. With that, the Data Annotation is simple: TimeStamp.

[Timestamp]
public byte[] RowVersion { get; set; }

Example 3-8. INSERT combined with SELECT to return new RowVersion

exec sp_executesql N
'insert [dbo].[People]([SocialSecurityNumber], [FirstName], [LastName])
values (@0, @1, @2)
select [RowVersion]
from [dbo].[People]
where @@ROWCOUNT > 0 and [SocialSecurityNumber] = @0',
N'@0 int,@1 nvarchar(max) ,@2 nvarchar(max) ',@0=12345678,@1=N'Rowan',@2=N'Miller'

Not only does Entity Framework tell the database to perform the INSERT, but it also requests the RowVersion value back. EF will always do this with a property that is flagged for concurrency, even if it is not a timestamp value. Even more critical are the UPDATE and DELETE commands, because here is where the

concurrency check occurs. We’ve added a new method to the app, UpdatePerson, shown in Example 3-9. 

Example 3-9. The UpdateTrip method

private static void UpdateTrip()
{
using (var context = new BreakAwayContext())
{
var trip = context.Trips.FirstOrDefault();
trip.CostUSD = 750;
context.SaveChanges();
}
}

Example 3-10 shows the SQL executed when SaveChanges is called in the UpdateTrip

method.

Example 3-10. UPDATE that filters on original RowVersion and returns new RowVersion

exec sp_executesql N'update [dbo].[Trips]
set [CostUSD] = @0
where (([Identifier] = @1) and ([RowVersion] = @2))
select [RowVersion]
from [dbo].[Trips]
where @@ROWCOUNT > 0 and [Identifier] = @1',
N'@0 decimal(18,2),@1 uniqueidentifier,@2 binary(8)',
@0=750.00,@1='D1086EFE-5C5B-405D-9F09-688981BB5B41',@2=0x0000000000001773

Notice the where predicate used to locate the trip being updated—it filters on the Identifier and the RowVersion. If someone else has modified the trip since it was retrieved by our method, the RowVersion will have changed and there will be no row that matches the filter. The UPDATE will fail and Entity Framework will throw an Optimistic ConcurrencyException.

Configuring TimeStamp/RowVersion with Fluent API
While the Data Annotation uses the term TimeStamp, the Fluent configuration uses the term RowVersion. To specify a RowVersion property, append the IsRowVersion() method to the Property. With DbModelBuilder, you configure the Property like this:

modelBuilder.Entity<Person>()
.Property(p => p.RowVersion).IsRowVersion();

 Inside an EntityTypeConfiguration<T> class the configuration looks like:

Property(p => p.RowVersion).IsRowVersion();

Convention and Configuration For Relationship

Example 1:

public class Destination
{
  public int DestinationId { get; set; }
  public string Name { get; set; }
  public string Country { get; set; }
  public string Description { get; set; }
  public byte[] Photo { get; set; }

  public List<Lodging> Lodgings { get; set; }
}

public class Lodging
{
  public int LodgingId { get; set; }
  public string Name { get; set; }
public bool IsResort { get; set; }
  public decimal MilesFromNearestAirport { get; set; }

  public Destination Destination { get; set; }// Same DB schema will be created without it.
}

private static void CreateNewDests()
        {
            Destination dest = new Destination
            {
                Name = "dest1"
            };
            List<Lodging> Lodgings = new List<Lodging>();
            Lodging lodging1 = new Lodging()
                     {
                         //Destination = dest,
                         IsResort = false,
                         Name = "lodging1"
                     };
            Lodging lodging2 = new Lodging()
                     {
                         //Destination = dest,
                         IsResort = false,
                         Name = "lodging2"
                     };

            Lodgings.Add(lodging1);
            Lodgings.Add(lodging2);
            dest.Lodgings = Lodgings;
            using (var context = new VetContext())
            {
                context.Dests.Add(dest);

                Console.WriteLine(context.Database.Connection.ConnectionString);

                int i = context.SaveChanges();
                Console.WriteLine("{0} records added...", i);
                Console.ReadLine();
            }
        }
//3 rows will created in 2 table.

by convention it will configure this as a one-to-many relationship. Based on this, Code First can also determine thatLodging is the dependent end of the relationship (the end with the foreign key) and Destination is the principal end (the end with the primary key). It therefore knows that the table Lodging maps to will need a foreign key pointing back to the primary key of Destination. You saw this played out in Chapter 2, where it created the Destination_DestinationId foreign key field in the Lodgings table.

Rules:

  • If your classes contain a reference and a collection navigation property, Code First assumes a one-to-many relationship.(example 1)

  • Code First will also assume a one-to-many relationship if your classes include a navigation property on only one side of the relationship (i.e., either the collection or the reference, but not both).(example 1 if destination remove lodging list . lodging keep the Destination property. will create same schema.)

  • If your classes include two collection properties, Code First will use a many-to-many relationship by default.

  • If your classes include two reference properties, Code First will assume a one-to-one relationship.

  • In the case of one-to-one relationships, you will need to provide some additional information so that Code First knows which entity is the principal and which is the dependent. You’ll see this in action a little later on in this chapter, in the Working with One-to-One Relationships section. If no foreign key property is defined in your classes, Code First will assume the relationship is optional (i.e., the one end of the relationship is actually zero-or-one as opposed to exactly-one).

  • In the Working with Foreign Keys section of this chapter, you will see that when you define a foreign key property in your classes, Code First uses the nullability of that property to determine if the relationship is required or optional.

Configuring Multiplicity with Data Annotations

Most of the multiplicity configuration needs to be done using the Fluent API. But we can use Data Annotations to specify that a relationship is required. This is as simple as placing the Required annotation on the reference property that you want to be required. Modify Lodging by adding the Required annotation to the Destination property (Example 4-3).

Example 4-3. Required annotation added to Destination property

public class Lodging
{
  public int LodgingId { get; set; }
  public string Name { get; set; }
  public string Owner { get; set; }
  public bool IsResort { get; set; }
  public decimal MilesFromNearestAirport { get; set; }

  [Required]
  public Destination Destination { get; set; }//Will be not null 
}

Configuring Multiplicity with the Fluent API

Configuring relationships with the Fluent API can look confusing if you haven’t taken the time to understand the fundamental ideas. We’ll lead you down the path to enlightenment.

When fixing relationships with Data Annotations, you apply annotations directly to the navigation properties. It’s very different with the Fluent API, where you are literally configuring the relationship, not a property. In order to do so, you must first identify the relationship. Sometimes it’s enough to mention one end, but most often you need to describe the complete relationship.

To identify a relationship, you point to its navigation properties. Regardless of which end you begin with, this is the pattern:

Entity.Has[Multiplicity](Property).With[Multiplicity](Property)

The multiplicity can be Optional (a property that can have a single instance or be null), Required (a property that must have a single instance), or Many (a property with a collection of a single type).

The Has methods are as follows:

  • HasOptional

  • HasRequired

  • HasMany

In most cases you will follow the Has method with one of the following With methods:

  • WithOptional

  • WithRequired

  • WithMany

Example 4-4 shows a concrete example using the existing one-to-many relationship between Destination and Lodging. This configuration doesn’t really do anything, because it is configuring exactly what Code First detected by convention. Later in this chapter, you will see that this approach is used to identify a relationship so that you can perform further configuration related to foreign keys and cascade delete.

Example 4-4. Specifying an optional one-to-many relationship

modelBuilder.Entity<Destination>()
  .HasMany(d => d.Lodgings)
  .WithOptional(l => l.Destination);

 

Example 4-5 shows what this same configuration would look like inside an EntityTypeConfiguration class rather than directly inside OnModelCreating.

Example 4-5. Specifying a relationship in an EntityConfiguration class

HasMany(d => d.Lodgings)
  .WithOptional(l => l.Destination);

 

This identifies a relationship that Destination Has. It has a Many relationship that is defined by its property, Lodgings. And the Lodgings end of the relationship comes along With a relationship (which is Optional) toDestination

 

 

 

Working with Foreign Keys

 

In the previous section you added some configuration to make the Lodging to Destination relationship required. Go ahead and remove this configuration so that we can observe the Code First conventions in action. With the configuration removed, add a DestinationId property into the Lodging class:

public int DestinationId { get; set; }

 

WHY FOREIGN KEY PROPERTIES?

It’s common when coding to want to identify a relationship with another class. For example, you may be creating a new Lodging and want to specify which Destination the Lodging is associated with. If the particular destination is in memory, you can set the relationship through the navigation property:

myLodging.Destination=myDestinationInstance;

However, if the destination is not in memory, this would require you to first execute a query on the database to retrieve that destination so that you can set the property. There are times when you may not have the object in memory, but you do have access to that object’s key value. With a foreign key property, you can simply use the key value without depending on having that instance in memory:

myLodging.DestinationId=3;

Additionally, in the specific case when the Lodging is new and you attach the pre-existing Destination instance, there are scenarios where Entity Framework will set the Destination’s state to Added even though it already exists in the database. If you are only working with the foreign key, you can avoid this problem.

Exploring Many-to-Many Relationships

Entity Framework supports many-to-many relationships. Let’s see how Code First responds to a many-to-many relationship between two classes when generating a database.

If you’ve had many-to-many relationships when using the database-first strategy, you may be familiar with the fact that Entity Framework can create many-to-many mappings when the database join table contains only the primary keys of the related entities. This mapping rule is the same for Code First.

Let’s add a new Activity class to the model. Activity, shown in Example 4-15, will be related to the Trip class. A Trip can have a number of Activities scheduled and an Activity can be scheduled for a variety of trips. Therefore Trip and Activity will have a many-to-many relationship.

Example 4-15. A new class, Activity

using System.ComponentModel.DataAnnotations; 
using System.Collections.Generic;

namespace Model
{
  public class Activity
  {
    public int ActivityId { get; set; }
    [Required,MaxLength(50)]
    public string Name { get; set; }

    public List<Trip> Trips { get; set; }
  }
}

 

There’s a List<Trip> in the Activity class. Let’s also add a List<Activity> to the Trip class for the other end of the many-to-many relationship:

public List<Activity> Activities { get; set; }

 

When you run the application again, Code First will recreate the database because of the model changes. Code First convention will recognize the many-to-many relationship and build a join table in the database with the appropriate keys of the tables it’s joining. The keys are both primary keys of the join table and foreign keys pointing to the joined tables, as shown in Figure 4-10.

 

Code First experience 

1、Create Code First Model Firstly.

public class Exam
    {
        public Exam()
        {
            this.ExamStus = new List<ExamStudent>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public virtual ICollection<ExamStudent> ExamStus { get; set; }
        
    }

public class ExamStudent
    {

        public int Id { get; set; }
        public string StuName { get; set; }
        public int ExamId { get; set; }
        public virtual Exam Exam { get; set; }
    }

2、Add Entity FrameWork reference use Nuget.

3、Add ExamContext class.

public class ExamContext:DbContext
    {
        public DbSet<Exam> Exams { get; set; }
    }

4、Write some CRUD code sample.

static void Main(string[] args)
        {
            Database.SetInitializer(new  DropCreateDatabaseIfModelChanges<ExamContext>());
            CreateExam();
            Console.ReadKey();
        }

        private static void CreateExam()
        {
            var exam = new Exam
            {
                 Address="wq1",
                  Name="second"
            };
            var stu1 = new ExamStudent()
            {
                StuName = "stu3",
                Exam = exam
            };
            var stu2 = new ExamStudent()
            {
                StuName = "stu4",
                Exam = exam
            };

            exam.ExamStus = new List<ExamStudent>();
            exam.ExamStus.Add(stu1);
            exam.ExamStus.Add(stu2);
            using (var context = new ExamContext())
            {
                context.Exams.Add(exam);
                context.SaveChanges();
            }
        }

5、no database and no connection string . after running . a database will be created in the sql express .

6、if you want to continue to use the new created database . following these steps .

* add <connectionstring> element to app.config.

<connectionStrings>
    <add name="ExamContext" connectionString="Data Source=.;Initial Catalog=TestSimpleCodeFirst.ExamContext;Integrated Security=True;MultipleActiveResultSets=True"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

* and use the setting 

Database.SetInitializer(new  DropCreateDatabaseIfModelChanges<ExamContext>());

drop db when model changes.

the table relationship diagram shows there is a forgein key between exam and examstudent .

but . even you remove the constraint of these table. it does not matter .

 

 

posted on 2012-07-21 16:29  malaikuangren  阅读(657)  评论(0编辑  收藏  举报