Mobiele apps programmeren met Xamarin – Entity Framework – CRUD

print

Deze handleiding maakt deel uit van het programmeertraject:


Inhoud


Wat vooraf ging


Inleiding

CRUD staat voor:

  • Create: records toevoegen
  • Read: records selecteren
  • Update: records wijzigen
  • Delete: records verwijderen

In deze handleiding bespreken we CRUD met Entity Framework.

Om eventuele fouten op te vangen gaan we gebruik maken van het using-statement.

Het using-statement roept automatisch een dispose-statement aan en dit zorgt ervoor dat de ongebruikte resources, ook als het fout loopt, worden “opgekuist”, vrijgegeven.

Het is een goede gewoonte om alle databankbewerkingen te plaatsen binnen een using-statement, maar u moet het dan wel consequent overal doen of u genereert fouten.

using (var context = new BloggingContext())
{
    …
}

Create (toevoegen)

We hebben reeds records toegevoegd bij de creatie van het model.

Onderstaand voorbeeld komt uit het Xamarin-vooorbeeld dat we aan het creëren zijn:

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestEF.Models;

namespace TestEF.Services
{
    public class DatabaseContext : DbContext
    {
        string _dbPath;

        public DatabaseContext(string dbPath)
        {
            _dbPath = dbPath;
            Database.EnsureDeleted();
            Database.EnsureCreated();
        }

        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite($"Filename={_dbPath}");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //Name
            modelBuilder.Entity<Blog>()
                .Property(b => b.Name)
                .IsRequired();

            modelBuilder.Entity<Blog>()
                .Property(b => b.Name)
                .HasMaxLength(100);

            //URL
            modelBuilder.Entity<Blog>()
                .Property(b => b.Url)
                .IsRequired();

            modelBuilder.Entity<Blog>()
                .Property(b => b.Url)
                .HasMaxLength(500);

            //Title Post
            modelBuilder.Entity<Post>()
                .Property(p => p.Title)
                .IsRequired();

            modelBuilder.Entity<Post>()
                .Property(p => p.Title)
                .HasMaxLength(100);

#if DEBUG
            modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Name="PCVO Groeipunt", Url = "https://www.pcvogroeipunt.be" });
            modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 2, Name="ICT-opleidingen", Url = "https://ictopleidingen.azurewebsites.net" });

            modelBuilder.Entity<Post>().HasData(
               new { BlogId = 1, PostId = 1, Title = "Post 1", Content = "Test 1" },
               new { BlogId = 1, PostId = 2, Title = "Post 2", Content = "Test 2" },
               new { BlogId = 2, PostId = 3, Title = "Post 3", Content = "Test 3" },
               new { BlogId = 2, PostId = 4, Title = "Post 4", Content = "Test 4" });
#endif
        }
    }
}

Wanneer we zelf, tijdens de uitvoering van het programma, willen gegevens toevoegen dan kan dit gelijkaardig.

using (var context = new BloggingContext())
{
    var blog = new Blog { Name="Test", Url = "http://test.com" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}
  • Maak gebruik van een using-statement om ongebruikte resources op te kuizen.
  • Er wordt een nieuwe instantie van de DbContext genomen: var context = new BloggingContext().
  • Er wordt een nieuwe blog aangemaakt en deze krijgt de gewenste waarden: var blog = new Blog { Name="Test", Url = "http://test.com" };.
  • Deze nieuwe Blog wordt toegevoegd aan (de entiteit/tabel) Blogs: context.Blogs.Add(blog);.
  • De DbContext/databank wordt bewaard: context.SaveChanges();

Uiteraard kunnen de waarden ook gelezen worden uit bv. tekstvakken: var blog = new Blog { Name = BlogNaam.Text, Url = BlogURL.Text" };.

Gerelateerde entiteiten

Indien nodig kan ook in één beweging gerelateerde gegevens worden toegevoegd.

using (var context = new BloggingContext())
{
    var blog = new Blog
    {
        Name = ".NET",
        Url = "http://test.com/dotnet",
        Posts = new List<Post>
        {
            new Post { Title = "Intro to C#" },
            new Post { Title = "Intro to VB.NET" },
            new Post { Title = "Intro to F#" }
        }
    };

    context.Blogs.Add(blog);
    context.SaveChanges();
}

Merk op dat het toevoegen en bewaren identiek is:

context.Blogs.Add(blog);
context.SaveChanges();

Read (selecteren)

Een enkele entiteit

In de praktische Xamarin uitwerking hebben we al meerdere selecties uitgevoerd, hieronder vindt u een overzicht en aanvulling.

Onderstaand voorbeeld laadt alle gegevens van de entiteit Blog met ToList().

using (var context = new BloggingContext())
{
    var blogs = context.Blogs.ToList();
}

Onderstaand voorbeeld laadt een specifieke Blog met Single(b => b.BlogId == 1)().

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);
}

Onderstaand voorbeeld filtert de gegevens van de entiteit Blog met Contains().

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Where(b => b.Url.Contains("dotnet"))
        .ToList();
}

Gerelateerde entiteiten

Het is uiteraard ook mogelijk om gegevens uit meerdere, gerelateerde entiteiten te selecteren.

Onderstaand voorbeeld selecteert gegevens uit de entiteiten Blog en de gerelateerde entiteit Post met Include.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ToList();
}

Onderstaand voorbeeld selecteert gegevens uit de entiteiten Blog en de gerelateerde entiteiten Post en Owner.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .Include(blog => blog.Owner)
        .ToList();
}

Onderstaand voorbeeld selecteert gegevens uit de entiteiten Blog en de gerelateerde entiteiten Post en de entiteit Author die gerelateerd is met Post.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .ToList();
}

Verdere voorbeelden vindt u hier.

Bovenstaande voorbeelden hebben allen volgende beperkingen:

  • U selecteert altijd alle eigenschappen (kolommen).
  • Gerelateerde eigenschappen (kolommen) zijn niet rechtstreeks te binden met XAML

Om deze beperkingen niet te hebben verkies ik te werken met LINQ to Entities.

In onze praktisch Xamarin voorbeeld hebben we dit al eens gebruikt.

using (var context = new BloggingContext())
{
    from b in context.Blogs
    join p in context.Posts
        on b.BlogId equals p.BlogId
    where b.BlogId == BlogItem.BlogId
    orderby p.Title descending, p.Content
    select new
    {
        Naam = b.Name,
        Titel = p.Title,
        Inhoud = p.Content
    }
}

Dit heeft veel weg van een SQL-commando en zal, voor zij die SQL kennen, meteen duidelijk zijn. Let op, de select staat hier achteraan.


Update (wijzigen)

Een update is te vergelijken met een toevoeging. Het verschil bestaat erin dat bij een update de te wijzigen instantie (record) reeds bestaat en niet wordt toegevoegd.

In onderstaand voorbeeld wordt eerst de Blog gezocht, op basis van een variabele blogId, nadien wordt de nieuwe waarde toegekend en de databank bewaard.

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(blogId);;
    blog.Url = "http://sample.com/blog";
    context.SaveChanges();
}

Delete (verwijderen)

Om te verwijderen moet u, net als bij een update, eerst bepalen wat u wilt verwijderen, nadien volgt een eenvoudige Remove().

using (var context = new BloggingContext())
{
    var blog = context.Blogs.First();
    context.Blogs.Remove(blog);
    context.SaveChanges();
}

Hoe zit het met gerelateerde entiteiten, worden die ook verwijderd?

Wel, het hangt ervan af.

  • Is de relatie Required (de Foreign key kan niet null zijn) dan worden de gerelateerde instanties (records) eveneens verwijderd. Dit wordt een Cascade Delete genoemd.
  • Is de relatie Optional (de Foreign key kan null zijn) dan worden Foreign key van de gerelateerde instanties (records) op null gezet.

Wilt u hier alles over weten, lees dan hier verder.


Meerdere operaties en slechts één SaveChanges

Het is, uiteraard, mogelijk om meerdere operaties uit te voeren en pas, op het einde van alle operaties te bewaren.

Bekijk het onderstaand voorbeeld maar eens.

using (var context = new BloggingContext())
{
    // seeding database
    context.Blogs.Add(new Blog { Url = "http://sample.com/blog" });
    context.Blogs.Add(new Blog { Url = "http://sample.com/another_blog" });
    context.SaveChanges();
}

using (var context = new BloggingContext())
{
    // add
    context.Blogs.Add(new Blog { Url = "http://sample.com/blog_one" });
    context.Blogs.Add(new Blog { Url = "http://sample.com/blog_two" });

    // update
    var firstBlog = context.Blogs.First();
    firstBlog.Url = "";

    // remove
    var lastBlog = context.Blogs.Last();
    context.Blogs.Remove(lastBlog);

    context.SaveChanges();
}

Geef een reactie

  • Abonneer je op deze website d.m.v. e-mail

    Voer je e-mailadres in om je in te schrijven op deze website en e-mailmeldingen te ontvangen van nieuwe berichten.