{"id":19029285,"url":"https://github.com/sulmar/ef-tutorial","last_synced_at":"2026-06-23T13:01:42.877Z","repository":{"id":94110060,"uuid":"78965365","full_name":"sulmar/ef-tutorial","owner":"sulmar","description":"Przewodnik po Entity Framework 6.x","archived":false,"fork":false,"pushed_at":"2021-04-20T06:44:18.000Z","size":54,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-21T20:13:31.331Z","etag":null,"topics":["csharp","entity-framework"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sulmar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-14T20:40:29.000Z","updated_at":"2021-04-20T06:44:21.000Z","dependencies_parsed_at":"2023-03-08T10:45:37.136Z","dependency_job_id":null,"html_url":"https://github.com/sulmar/ef-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sulmar/ef-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sulmar%2Fef-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sulmar%2Fef-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sulmar%2Fef-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sulmar%2Fef-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sulmar","download_url":"https://codeload.github.com/sulmar/ef-tutorial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sulmar%2Fef-tutorial/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34690771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","entity-framework"],"created_at":"2024-11-08T21:13:46.766Z","updated_at":"2026-06-23T13:01:42.843Z","avatar_url":"https://github.com/sulmar.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Instalacja biblioteki\n\n~~~ bash\nPM\u003e Install-Package EntityFramework\n~~~\n\n# Utworzenie kontekstu\n\n~~~ csharp\npublic class MyContext : DbContext\n{\n    public MyContext(DbConnection connection, bool contextOwnsConnection)\n      :base(connection, contextOwnsConnection)\n    { }\n\n    public DbSet\u003cCustomer\u003e Customers { get; set; }\n    public DbSet\u003cOrder\u003e Orders { get; set; }\n}\n~~~\n\n# Połączenie do bazy danych\n\n~~~ xaml\n \u003cconnectionStrings\u003e\n    \u003cadd name=\"MyConnection\" providerName=\"System.Data.SqlClient\" connectionString=\"Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=MyDb;Integrated Security=True\" /\u003e\n  \u003c/connectionStrings\u003e\n~~~\n\n## Algorytm wyszukiwania bazy danych\n\n1. Jeśli w konstruktorze DbContext podano nazwę połączenia to szuka jej w pliku konfiguracynym app.config w sekcji _connectionStrings_ \n\n2. Jeśli użyto domyślnego konstruktora DbContext to szuka pliku konfiguracynym app.config nazwy klasy DbContext w sekcji _connectionStrings_  \n\n3. Szuka instancji SQL Express \n\n4. Szuka bazy danych LocalDb o adresie (localdb)\\mssqllocaldb\n\n\n## Wyświetlenie parametrów połączenia\n\n~~~ csharp\nConsole.WriteLine(context.Database.Connection.ConnectionString);\n~~~\n\n\n\n- Azure Data Studio\n\nhttps://docs.microsoft.com/en-us/sql/azure-data-studio/download?view=sql-server-2017\n\n\n\n\n\n# DbContext\nKlasa DbContext jest główną częścią Entity Framework. Instacja DbContext reprezentuje sesję z bazą danych.\n\n## Zadania DbContext:\n 1. **Querying** - Konwertuje Linq-To-Entities do zapytań SQL i wysyła je do bazy danych\n 2. **Change Tracking** - śledzenie zmian\n 3. **Persisting Data** - Zapisywanie zmian encji w bazie danych\n 4. **Caching** - pamięć podręczna pierwszego poziomu\n 5. **Manage Relationship** - zarządzanie relacjami\n 6. **Transactions** - zarządzanie transakcjami\n 7. **Object Materialization** - konwersja surowych danych do obiektów encji\n\nModels.cs\n\n~~~ csharp\n\npublic class Order\n{\n    public int OrderId { get; set; }   \n    public string OrderNumber { get; set; }  \n    public DateTime OrderDate { get; set; }\n    public DateTime DeliveryDate? { get; set; }\n    public Customer Customer { get; set; }\n}\n\npublic class Customer\n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public bool IsDeleted { get; set; }\n}\n~~~\n\n\nMyContext.cs\n\n~~~ csharp\npublic class MyContext : DbContext\n{\n    public DbSet\u003cCustomer\u003e Customers { get; set; }\n    public DbSet\u003cOrder\u003e Orders { get; set; }\n\n    public CustomersContext() \n        : base(\"MyDbConnection\")\n    {\n    }\n}\n~~~\n\n\n## Właściwości DbContext\n| Metoda | Użycie |\n|---|---|\n| ChangeTracker | Dostarcza informacje i operacje do śledzenie obiektów  |\n| Database | Dostarcza informacje o bazie danych i umożliwia operacje na bazie danych |\n| Configuration | Konfiguracja opcji |\n\n## Fabryka\nJeśli korzystamy z migracji, a konstuktor naszej klasy DbContext posiada parametr(y) nalezy utworzyć fabrykę:\n\n~~~ csharp\n    \n    public class MyContextFactory : IDbContextFactory\u003cTransportContext\u003e\n    {\n        public MyContext Create()\n        {\n            return new MyContext(new TransportDbInitializer());\n        }\n    }\n    \n~~~\n\n# Konwencje\n\n## Odkrywanie typów (Type Discovery)\nEF wyszukuje typy, która wskazane są poprzez właściwość DbSet i tworzy odpowiadające im tabele.\nUwględnia również referencyjne typy właściwości, które nie są wskazane przez DbSet oraz typy, które dziedziczą po klasie bazowej wskazanej przez DbSet.\n\n## Konwencja nazywania tabel (Table Name Convention)\nCode First tworzy tabele o nazwach w liczbie mnogiej od nazwy encji.\n\n## Nazwy kolum\nEF wyszukuje wszystkie publiczne właściwości, które posiadają get i set i tworzy kolumny o takich samych nazwach.\n\n## Typy danych i rozmiar kolumn\n| .NET | SQL |\n|---|---|\n| string | nvarchar(max) |\n| decimal | decimal(18, 2) |\n| double | float |\n| int | int |\n| bool | bit |\n| DateTime | datetime |\n| byte[] | varbinary(max) |\n\n## Klucz podstawowy (Primary Key)\nEF wyszukuje właściwość, której nazwa kończy się na **ID**. Wielkość liter nie ma znaczenia.\n\n## Klucze obce (Foreign Key)\n\n### Konwencja relacji Jeden-do-wielu\n\n#### Konwencja 1\nEncja zawiera navigation property.\n\n``` csharp\npublic class Order\n{\n    public int OrderId { get; set; }   \n    public string OrderNumber { get; set; }  \n\n    public Customer Customer { get; set; } // Navigation property\n}\n\npublic class Customer\n{\n    public int CustomerId { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n}\n\n```\nZamówienie zawiera referencje do navigation property typu klient. EF utworzy shadow property CustomerId w modelu koncepcyjnym, które będzie mapowane do kolumny CustomerId w tabeli Orders.\n\n#### Konwencja 2\nEncja zawiera kolekcję.\n\n``` csharp\npublic class Order\n{\n    public int OrderId { get; set; }       \n    public string OrderNumber { get; set; } \n}\n\npublic class Customer\n{\n    public int CustomerId { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n\n    public List\u003cOrder\u003e Orders { get; set; }\n}\n\n```\n\nW bazie danych będzie taki sam rezultat jak w przypadku konwencji 1.\n\n#### Konwencja 3\n\nRelacja zawiera navigation property po obu stronach. W rezultacie otrzymujemy połączenie konwencji 1 i 2.\n\n\n``` csharp\npublic class Order\n{\n    public int OrderId { get; set; }       \n    public string OrderNumber { get; set; } \n\n    public Customer Customer { get; set; } // Navigation property\n}\n\npublic class Customer\n{\n    public int CustomerId { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n\n    public List\u003cOrder\u003e Orders { get; set; }\n}\n\n```\n\n#### Konwencja 4\nKonwencja z uzyciem wlasciwosci foreign key\n\n\n``` csharp\npublic class Order\n{\n    public int OrderId { get; set; }       \n    public string OrderNumber { get; set; } \n\n    public int CustomerId { get; set; }  // Foreign key property\n    public Customer Customer { get; set; } // Navigation property\n}\n\npublic class Customer\n{\n    public int CustomerId { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n\n    public List\u003cOrder\u003e Orders { get; set; }\n}\n\n```\n\n\n### Konwencja relacji Jeden-do-jeden\n\n``` csharp\npublic class Order\n{\n    public int OrderId { get; set; }       \n    public string OrderNumber { get; set; } \n\n    public Payment Payment { get; set; } // Navigation property\n}\n\npublic class Payment\n{\n    public int PaymentId { get; set; }\n    public decimal Amount { get; set; }\n\n    public int OrderId { get; set; }\n    public Order Order { get; set; }\n}\n```\n\n### Konwencja relacji wiele-do-wielu\n\n\n``` csharp\npublic class User\n{\n    public int Id { get; set; }       \n    public string Login { get; set; } \n\n    public ICollection\u003cRole\u003e Roles { get; set; } // Navigation property\n}\n\npublic class Role\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n\n    public ICollection\u003cUser\u003e Users { get; set; }  // Navigation property\n}\n```\n\nZostanie automatycznie utworzona tabela pośrednia\n\n## Konfiguracja relacji Jeden-do-wielu z uzyciem Fluent API\n\n\n``` csharp\n   protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.Entity\u003cOrder\u003e()\n                .HasOne\u003cCustomer\u003e()\n                .WithMany(c=\u003ec.Orders)\n                .HasForeignKey(p=\u003ep.CustomerId);\n``` \n\n\nAlternatywnie mozna wyjsc od drugiej strony\n``` csharp\n            modelBuilder.Entity\u003cCustomer\u003e()\n                .HasMany(c=\u003ec.Orders)\n                .WithOne(o=\u003eo.Customer)\n                .HasForeignKey(o=\u003eo.CustomerId);\n\n\n        }\n```\n\n## Konfiguracja kaskadowego usuwania z Fluent API\n\n``` csharp\nmodelBuilder.Entity\u003cCustomer\u003e()\n                .HasMany(c=\u003ec.Orders)\n                .WithOne(o=\u003eo.Customer)\n                .HasForeignKey(o=\u003eo.CustomerId)\n                .OnDelete(DeleteBehavior.Cascade);\n```\n\nRodzaje:\n- Cascade - usuwa wszystkie encje wraz z encją nadrzędną\n- ClientSetNull - klucze obce w encjach zaleznych będą ustawione na null\n- Restrict - blokuje kaskadowe usuwanie\n- SetNull - klucze obce w encjach zaleznych będą ustawione na null\n\n\n## Konfiguracja jeden-do-jeden z Fluent API\n\n\n``` csharp\n modelBuilder.Entity\u003cOrder\u003e()\n                .HasOne\u003cPayment\u003e()\n                .WithOne(p=\u003ep.Order)\n                .HasForeignKey\u003cPayment\u003e(p=\u003ep.PaymentId);\n```\n\n## Konfiguracja wiele-do-wiele z Fluent API\n\n### Podstawowa konfiguracja\n\n``` csharp\n\nmodelBuilder.Entity\u003cUser\u003e()\n                .HasMany(e =\u003e e.Roles)\n                .WithMany(e =\u003e e.Users);\n```\n\nPowstanie tabela pośrednicząca o nazwie UserRoles\n\n\nJeśli zamienimy miejscami pola otrzymamy inną nazwę tabeli:\n\n``` csharp\n\nmodelBuilder.Entity\u003cRole\u003e()\n                .HasMany(e =\u003e e.Users)\n                .WithMany(e =\u003e e.Roles);\n```\nPowstanie tabela pośrednicząca o nazwie RoleUsers\n\n### Własna nazwy tabeli\n\n``` csharp\nmodelBuilder.Entity\u003cUser\u003e()\n                .HasMany(e =\u003e e.Roles)\n                .WithMany(e =\u003e e.Users)\n                .Map(m=\u003e\n                {\n                    m.ToTable(\"UsersInRoles\");\n                });\n```\n\nPowstanie tabela pośrednicząca o nazwie UsersInRoles\n\n### Własne klucze obce\n\n\n``` csharp\nmodelBuilder.Entity\u003cUser\u003e()\n                .HasMany(e =\u003e e.Roles)\n                .WithMany(e =\u003e e.Users)\n                .Map(m=\u003e\n                {\n                    m.MapLeftKey(\"UserId\");\n                    m.MapRightKey(\"RoleId\");\n                });\n\n```\n\n## Typ złożony (Complex Type)\nJeśli klasa nie ma klucza podstawowego.\n\n\n\n# Śledzenie (Tracking)\n\n## AutoDetectChanges\n\nDomyślnie śledzenie zmian jest włączone. W celu zwiększenia wydajności, zwłaszcza przy dodawaniu dużej ilości encji warto wyłączyć automatyczne wykrywanie zmian:\n\n\n~~~ csharp\nusing (var context = new MyContext())\n{\n    context.Configuration.AutoDetectChangesEnabled = false;\n}\n~~~\n\nPamiętaj o wywołaniu metody _DetectChanges()_ przed _SaveChanges()_\n\nPrzykład:\n~~~ csharp\nusing (var context = new MyContext())\n{\n\n            using (var context = new MyContext())\n            {\n                try\n                {\n                    context.Configuration.AutoDetectChangesEnabled = false;\n \n                    foreach (var product in context.Products)\n                    {\n                        product.UnitPrice = 1.0m;\n                    }\n                }\n                finally\n                {\n                    context.Configuration.AutoDetectChangesEnabled = true;\n                }\n \n                context.ChangeTracker.DetectChanges();\n                context.SaveChanged();\n            }\n        }\n~~~\n\n### Lokalne wyłączenie śledzenia\n\n~~~ csharp\nusing (var context = new MyContext())\n{\n    var blogs = context.Customers\n        .AsNoTracking()\n        .ToList();\n}\n~~~\n\n\n\n### Pobranie informacji o encjach\n\n~~~ csharp\n Console.WriteLine(\n   $\"Tracked Entities: {context.ChangeTracker.Entries().Count()}\");\n\nforeach (var entry in context.ChangeTracker.Entries())\n{\n    Console.WriteLine($\"Entity: {entry.Entity.GetType().Name}, \n                        State: {entry.State.ToString()} \");\n}\n\n~~~\n\n\n\n## Praca z odłączonymi encjami\n\n\n### Attach()\nMetoda *Attach()* przyłącza odłączony graf encji i zaczyna go śledzić.\n\nMetoda *Attach()* ustawia główną encję na stan Added niezależnie od tego, czy posiada wartość klucza. Jeśli encje dzieci posiadają wartość klucza wówczas zaznaczane są jako *Unchanged*, a w przeciwnym razie jako *Added*.\n\n\n``` csharp\ncontext.Attach(entityGraph).State = state;\n```\n\n| Attach()  | Root entity with Key value  | Root Entity with Empty or CLR default value  | Child Entity with Key value  |  Child Entity with empty or CLR default value |\n|---|---|---|---|---|\n| EntityState.Added  | Added  | Added  | Unchanged  | Added  |\n| EntityState.Modified  | Modified  | Exception  | Unchanged  | Added  |\n| EntityState.Deleted  | Deleted  | Exception  | Unchanged  | Added  |\n\n\n\n### Entry\n\n``` csharp\ncontext.Entry(order).State = EntityState.Modified\n```\n\nWyrażenie przyłącza encję do kontekstu i ustawia stan na **Modified**. Ignoruje wszystkie pozostałe encje.\n\n### Add()\nMetody *DbContext.Add()* i *DbSet.Add()* przyłączają graf encji do kontekstu i ustawiają stan encji na **Added** niezależnie od tego czy posiadają wartość klucza czy też nie.\n\n| Method | Root entity with/out Key value  | \tRoot entity with/out Key |\n|---|---|---|\n| DbContext.Add  | Added  | Added  | \n\n\n### Update()\n\nMetoda *Update()* przyłącza graf encji do kontekstu i ustawia stan poszczególnych encji zależnie od tego czy jest ustawiona wartość klucza.\n\n| Update()  | Root entity with Key value  | Root Entity with Empty or CLR default value  | Child Entity with Key value  |  Child Entity with empty or CLR default value |\n|---|---|---|---|---|\n| DbContext.Update  | Modified  | Added  | Modified  | Added  |\n\n\n\n### Delete()\n\nMetoda *Delete()* ustawia stan głównej encji na **Deleted**.\n\n| Delete()  | Root entity with Key value  | Root Entity with Empty or CLR default value  | Child Entity with Key value  |  Child Entity with empty or CLR default value |\n|---|---|---|---|---|\n| DbContext.Delete  | Deleted  | Exception  | Unchanged  | Added  |\n\n\n\n\n\n## Change Tracker\n\nOdczytanie stanu encji\n\n~~~ csharp\n\nTrace.WriteLine(context.Entry(customer).State);\nforeach (var property in context.Entry(customer).Properties)\n{\n    Trace.WriteLine($\"{property.Metadata.Name} {property.IsModified} {property.OriginalValue} -\u003e {property.CurrentValue}\");\n}\n\n~~~\n\n\n## Surowy SQL\n\n### Uruchomienie zapytania SQL i pobranie wyników\n\n~~~ csharp\npublic IEnumerable\u003cCustomer\u003e Get(string lastname)\n{\n    string sql = $\"select * from dbo.customers where LastName = '{lastname}'\";\n    return context.Database.SqlQuery\u003cCustomer\u003e(sql);\n}\n~~~\n\n### Uruchomienie procedury składowanej\n~~~ csharp\nusing (var context = new SampleContext())\n{\n    var books = context.Database\n        .SqlQuery(\"GetAllCustomers\")\n        .ToList();\n}\n~~~\n\n### Uruchomienie procedury składowanej z parametrami\n\n~~~ csharp\nusing (var context = new SampleContext())\n{\n    var city = new SqlParameter(\"@City\", \"Warsaw\");\n    var customers = context\n        .SqlQuery(\"GetCustomersByCity @City\" , city)\n        .ToList();\n}\n~~~\n\n\n### Typy anonimowe i pobieranie wartości\n~~~ csharp\nvar orderHeaders = db.Database.SqlQuery(\n                    @\"select c.Name as CustomerName, o.DateCreated, sum(oi.Price) as TotalPrice, \n                    count(oi.Price) as TotalItems\n                    from  OrderItems  oi \n                    inner join Orders o on oi.OrderId = o.OrderId\n                    inner join Customers c on o.CustomerId = c.CustomerId\n                    group by oi.OrderId, c.Name, o.DateCreated\");\n~~~\n\n\n\n\n## Indeksy\n\n~~~ csharp\n\nclass EmployeeConfiguration : EntityTypeConfiguration\u003cEmployee\u003e\n{\n    public EmployeeConfiguration()\n    {\n\n        HasIndex(p =\u003e p.Email)                \n            .IsUnique();\n\n    }\n}\n\n~~~\n\n# Migracje\n\n\n## Przydatne polecenia\n- ``` Enable-Migrations ``` - włączenie migracji\n- ``` Add-Migration {migration} ``` - utworzenie migracji\n- ``` Add-Migration {migration} -force ``` - ponowne utworzenie migracji\n- ``` Update-Database ``` - aktualizacja bazy danych do najnowszej wersji\n- ``` Update-Database -script ``` - wygenerowanie skryptu do aktualizacji bazy danych do najnowszej wersji\n- ``` Update-Database -verbose ``` - aktualizacja bazy danych do najnowszej wersji + wyświetlanie logu\n- ``` Update-Database -TargetMigration: {migration} ``` - aktualizacja bazy danych do wskazanej migracji\n- ``` Update-Database -SourceMigration: {migrationA} -TargetMigration: {migrationB}  ```  - aktualizacja bazy danych \npomiędzy migracjami\n- ``` Update-Database -TargetMigration: $InitialDatabase ``` - aktualizacja bazy danych do pustej bazy danych\npomiędzy migracjami\n- ``` Update-Database -SourceMigration: $InitialDatabase -script``` - wygenerowanie kompletnego skryptu od pustej bazy danych\n\n\n### Utworzenie triggera\n1. Utwórz folder np. Scripts i plik OnDeleteOrderDetail.sql\n\n~~~ sql\nCREATE TRIGGER OnDeleteOrderDetail\n    ON [dbo].[OrderDetails]\n    FOR DELETE\nAS\nUPDATE [dbo].[Orders] SET ModifiedAt = getdate() WHERE Id = deleted.OrderId\n~~~\n\n2. Ustaw Build Action na Embedded Resource\n\n\n3. Utwórz klasę migracji\n\n~~~ csharp\npublic partial class AddTriggerOnDeleteOrderDetails : DbMigration\n    {\n        public override void Up()\n        {\n            SqlResource(\"MyApp.Scripts.201609301218380_AddTriggerOnDeleteOrderDetail_Up.sql\", suppressTransaction: true);\n        }\n        \n        public override void Down()\n        {\n            Sql(\"IF OBJECT_ID ('[OnDeleteOrderDetail]', 'TR') IS NOT NULL DROP TRIGGER OnDeleteOrderDetail\");\n        }\n    }\n\n~~~\n\n### Utworzenie procedury składowanej\n\n~~~ chsarp\n\npublic override void Up() \n{\n  CreateStoredProcedure(\n    \"MyStoredProcedure\",\n    p =\u003e new\n    {\n        id = p.Int()\n    },\n    @\"SELECT some-data FROM my-table WHERE id = @id\"\n  );\n}\n\npublic override void Down() \n{\n  DropStoredProcedure(\"MyStoredProcedure\");\n}\n\n~~~\n\n\n## Inicjalizatory\n\n### Wbudowane inicjalizatory\n\n| Typ | Opis |\n|---|---|\n| CreateDatabaseIfNotExists | utwórz bazę danych jeśli nie istnieje |\n| DropCreateDatabaseAlways | zawsze usuń i utwórz bazę danych |\n| DropCreateDatabaseIfModelChanges | usuń i utwórz bazę danych jeśli nastąpiły zmiany w modelu |\n\n\n### Ustawienie inicjalizatora w kodzie\n\n~~~ csharp\n public class MyContext : DbContext\n {\n     public MyContext() : base(\"MyDbConnection\")\n     {\n         Database.SetInitializer(new DropCreateDatabaseIfModelChanges\u003cMyContext\u003e());\n     } \n }\n~~~\n\n### Ustawienie inicjalizatora w pliku konfiguracyjnym\n\n~~~ xml\n\u003centityFramework\u003e\n        \u003ccontexts\u003e\n           \u003ccontext type=\"MyApp.MyContext, MyContext\"\u003e\n           \u003cdatabaseInitializer type=\"System.Data.Entity.DropCreateDatabaseAlways`1[[MyApp.MyContext, MyApp]], EntityFramework\" /\u003e\n           \u003c/context\u003e\n        \u003c/contexts\u003e\n    \u003c/entityFramework\u003e\n    \n~~~\n\n### Własny inicjalizator\n\n~~~ csharp\npublic class MyDbInitializer : IDatabaseInitializer\u003cMyContext\u003e\n    {\n        public void MyDbInitializer(MyContext context)\n        {\n            if (!context.Database.Exists() || !context.Database.CompatibleWithModel(true))\n            {\n                context.Database.Delete();\n                context.Database.Create();\n            }\n            // context.Database.ExecuteSqlCommand(\"Custom SQL Command here\");\n        }\n    }\n~~~\n\n\n\n### Wyłączenie inicjalizatorów\n\n~~~ csharp\npublic MyContext() : base(\"MyDbConnection\")\n{\n    Database.SetInitializer\u003cMyContext\u003e(null);\n }\n ~~~\n    \n### Rozszerzenie wbudowanego inicjalizatora\n\nPrzykład wypełnienia danych\n\n~~~ csharp\n public class MyDbInitializer : CreateDatabaseIfNotExists\u003cMyContext\u003e\n    {\n        private readonly CustomerFaker customerFaker;\n        \n        public MyDbInitializer(CustomerFaker customerFaker)\n        {\n            this.customerFaker = customerFaker;  \n        }\n\n        protected override void Seed(TransportContext context)\n        {\n            context.Customers.AddRange(customerFaker.Generate(1000));\n         \n\n            base.Seed(context);\n        }\n\n    }\n~~~\n\n## Śledzenie zapytań SQL\n\n\n### Logowanie\n\n~~~ csharp\npublic MyContext()\n{\n    this.Database.Log += Console.WriteLine;\n}\n~~~\n\n### Formatowanie logów\n\nUtworzenie własnego formattera\n~~~ csharp\n\npublic class OneLineFormatter : DatabaseLogFormatter \n{ \n    public OneLineFormatter(DbContext context, Action\u003cstring\u003e writeAction) \n        : base(context, writeAction) \n    { \n    } \n \n    public override void LogCommand\u003cTResult\u003e( \n        DbCommand command, DbCommandInterceptionContext\u003cTResult\u003e interceptionContext) \n    { \n        Write(string.Format( \n            \"Context '{0}' is executing command '{1}'{2}\", \n            Context.GetType().Name, \n            command.CommandText.Replace(Environment.NewLine, \"\"), \n            Environment.NewLine)); \n    } \n \n    public override void LogResult\u003cTResult\u003e( \n        DbCommand command, DbCommandInterceptionContext\u003cTResult\u003e interceptionContext) \n    { \n    } \n}\n~~~\n\nRejestracja:\n\n~~~ csharp\npublic class MyDbConfiguration : DbConfiguration \n{ \n    public MyDbConfiguration() \n    { \n        SetDatabaseLogFormatter((context, writeAction) =\u003e new OneLineFormatter(context, writeAction)); \n    } \n}\n~~~\n\n\n## Ładowanie powiązanych encji\n\n### Zachłanne ładowanie (Eager Loading)\n\n#### Ładowanie powiązanej właściwości\n\n~~~ csharp\nusing (var context = new RentContext())\n{\n    var rentals = context.Vehicle\n        .Include(p =\u003e p.Owner)                          \n        .ToList();\n}\n~~~\n\n\n#### Ładowanie zagnieżdżonych encji\n\n~~~ csharp\nusing (var context = new RentContext())\n{\n    var rentals = context.Vehicle\n        .Include(p =\u003e p.Owner).Select(b =\u003e b.Rentee).Include(b =\u003e b.Address);                               \n        .ToList();\n}\n~~~\n\n### Leniwe ładowanie (Lazy Loading)\n\nMyContext.cs\n\n~~~ csharp\npublic MyContext()\n    : base(\"MyDbConnection\")\n{\n    this.Configuration.LazyLoadingEnabled = true;\n    this.Configuration.ProxyCreationEnabled = true;\n}\n~~~\n\nWłaściwości muszą być oznaczone jako **publiczne** i **wirtualne**. W przeciwnym razie Lazy Loading nie będzie działać!\n\n~~~ csharp\npublic class Vehicle : Base\n{\n   public int Id { get; set; }\n\n   public virtual Employee Owner { get; set; }\n\n   public virtual ICollection\u003cEmployee\u003e Passangers { get; set; }\n}\n~~~\n\n### Jawne ładowanie (Explicit Loading)\n\n#### Ładowanie powiązanej encji\n\n~~~ csharp\ncontext.Entry(vehicle).Reference(p =\u003e p.Owner).Load();\n~~~\n\n### Ładowanie powiązanej kolekcji\n \n ~~~ csharp\n context.Entry(vehicle).Collection(p =\u003e p.Passangers).Load();\n~~~\n\n### Filtrowanie ładowanej kolekcji\n\n~~~ csharp\ncontext.Entry(vehicle)\n    .Collection(p =\u003e p.Passangers)\n    .Query()\n    .Where(p=\u003ep.Gender = Gender.Female)\n    .Load();\n~~~\n\n## Transakcje\n\n### Transakcje bazy danych\n\n~~~ csharp\n\nprivate void Save(Order order)\n{\n    using (var context = new MyContext())\n    using (var transaction = context.Database.BeginTransaction())\n    {\n        try\n        {\n            context.Orders.Add(order);\n            context.SaveChanges();\n            \n            context.Customers.Add(order.Customer);\n            context.SaveChanges();\n            \n            transaction.Commit();\n        }\n        catch(Exception)\n        {\n            transaction.Rollback();\n        }\n    }\n}\n\n~~~\n\n### Rozproszone transakcje\n\nDodaj referencję do _System.Transactions_\n\n\n~~~ csharp \n\nprivate static void Save(Order oder)\n{\n    using (var scope = new TransactionScope())\n    {\n        using (var context1 = new OrdersContext())\n        {\n            context1.Orders.Add(order);      \n            context1.SaveChanges();\n        }\n \n        using (var context2 = new CustomersContext())\n        {\n            context2.Customers.Add(order.Customer);\n            context2.SaveChanges();\n        }\n \n        scope.Complete();\n    }\n}\n~~~\n\nuwaga: w przypadku wykorzystania transakcji w metodzie asynchronicznej otrzymamy błąd. \nDlatego należy dodać parametr w konstruktorze:\n\n~~~ csharp\nvar transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)\n~~~\n     \n\n## Współbieżność\n\n### Token\n\n#### Konfiguracja za pomocą atrybutu\n\n~~~ csharp\npublic class Employee\n   {\n       public int Id { get; set; }\n \n       [ConcurrencyCheck]\n       public string FirstName { get; set; }\n       public string LastName { get; set; }\n   }\n~~~\n\n#### Konfiguracja za pomocą FluentAPI\n\n~~~ csharp\nclass EmployeeConfiguration : EntityTypeConfiguration\u003cEmployee\u003e\n    {\n        public EmployeeConfiguration()\n        {\n            Property(p =\u003e p.FirstName)\n                .IsConcurrencyToken();\n        }\n    }\n~~~   \n   \n#### Wykrywanie kolizji\n\n~~~ csharp\nprivate static void ConcurencyTest()\n   {\n       using (var context = new MyContext())\n       {\n           var employee = context.Empoyees.Find(1);\n           employee.FirstName = \"John\";\n\n           bool saveFailed;\n           do\n           {\n               saveFailed = false;\n\n               try\n               {\n                   context.SaveChanges();\n               }\n               catch (DbUpdateConcurrencyException ex)\n               {\n                   saveFailed = true;\n\n                   ex.Entries.Single().Reload();\n               }\n\n           } while (saveFailed);\n       }\n   }\n   \n~~~ \n\n### RowVersion\n\n####  Konfiguracja za pomocą atrybutu\n\n~~~ csharp\npublic class Employee\n{\n    [Timestamp]\n    public byte[] RowVersion { get; set; }\n}\n~~~\n\n####  Konfiguracja za pomocą FluentApi\n   \n~~~ csharp\npublic class Employee\n{\n    public int Id { get; set; }\n    public string FirstName { get; set; }\n    public string LastName { get; set; }\n    public byte[] RowVersion { get; set; }\n}\n~~~\n\n~~~ csharp\n\nclass EmployeeConfiguration : EntityTypeConfiguration\u003cEmployee\u003e\n{\n   public EmployeeConfiguration()\n   {\n       Property(p =\u003e p.RowVersion)\n          .IsConcurrencyToken()\n          .IsRowVersion();\n   }\n}\n\n~~~\n\n## Mapowanie operacji CRUD na procedury składowane\n\n### Konfiguracja FluentApi\n~~~ csharp\nclass EmployeeConfiguration : EntityTypeConfiguration\u003cEmployee\u003e\n    {\n        public EmployeeConfiguration()\n        {\n            MapToStoredProcedures();\n        }\n    }\n~~~\n\nUtworzone zostaną procedury składowane.\n\n### Modyfikacja nazw\n\nModyfikacja nazw procedur składowanych\n\n~~~ csharp\nclass EmployeeConfiguration : EntityTypeConfiguration\u003cEmployee\u003e\n    {\n        public EmployeeConfiguration()\n        {\n            MapToStoredProcedures(s =\u003e\n             {\n                 s.Update(u =\u003e u.HasName(\"modify_employee\"));\n                 s.Delete(d =\u003e d.HasName(\"delete_employee\"));\n                 s.Insert(i =\u003e i.HasName(\"insert_employee\"));\n             });\n        }\n    }\n~~~\n\n## Odłączone encje\n\n### Zapis odłączonej encji z użyciem biblioteki GraphDiff\n\nInstalacja biblioteki\n~~~ bash\nPM\u003e Install-Package RefactorThis.GraphDiff\n~~~\n\n~~~ csharp\nprivate static void GraphDiffTest()\n{\n    Artist artist = new Artist { ArtistId = 1, FirstName = \"The Artist Formerly Known as Prince\" };\n\n    using (var context = new MusicStoreContext())\n    {\n        context.UpdateGraph\u003cArtist\u003e(artist, map =\u003e map\n               .OwnedCollection(p =\u003e p.Albums));\n\n        context.SaveChanges();\n    }\n}\n~~~\n\nhttp://blog.brentmckendrick.com/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsulmar%2Fef-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsulmar%2Fef-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsulmar%2Fef-tutorial/lists"}