Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

finish xamarin getting started article and code sample #2497

Merged
merged 1 commit into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
197 changes: 197 additions & 0 deletions entity-framework/core/get-started/xamarin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
---
title: Getting Started with EF Core and Xamarin - EF Core
author: codemillmatt
ms.date: 07/07/2020
ms.author: masoucou
uid: core/get-started/xamarin
---

# Getting Started with EF Core and Xamarin

In this tutorial, you create a [Xamarin.Forms](/xamarin/get-started/what-is-xamarin-forms) application that performs data access against a SQLite database using Entity Framework Core.

You can follow the tutorial by using Visual Studio on Windows or Visual Studio for Mac.

> [!TIP]
> You can view this article's [sample on GitHub](https://github.com/dotnet/EntityFramework.Docs/tree/master/samples/core/Xamarin).

## Prerequisites

Install one of the below:

* [Visual Studio 2019 version 16.3 or later](https://www.visualstudio.com/downloads/) with this workload:
* **Mobile Development with .NET**
* [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/)

This [documentation provides detailed step-by-step installation instructions](/xamarin/get-started/installation) for each platform.

## Download and run the sample project

To run and explore this sample application, download the code on GitHub.

Once downloaded, open the solution file `EFGettingStarted.sln` in Visual Studio or Visual Studio for Mac and run the application on the platform of your choice.

When the app first starts, it will populate the local SQLite database with two entries representing blogs.

![Screenshot of all blogs list page](_static/xamarin-tutorial-1.png)

Click the **Add** button in the toolbar.

A new page will appear that allows you to enter information about a new blog.

![Screenshot of new blog edit page](_static/xamarin-tutorial-2.png)

Fill out all the info and click **Save** from the toolbar. The new blog will save to the app's SQLite database and will show in the list.

You can click on one of the blog entries in the list and see any posts for that blog.
codemillmatt marked this conversation as resolved.
Show resolved Hide resolved

![Screenshot of blog posts list page](_static/xamarin-tutorial-3.png)

Click **Add** in the toolbar.

A page then appears that allows you to fill out information about a new blog post.

![Screenshot of add new post page](_static/xamarin-tutorial-4.png)

Fill out all the information and click **Save** in the toolbar.

The new post will be associated to the blog post you clicked on in a previous step and will save to the app's SQLite database and show in the list.

Go back to the blog list page. And click **Delete All** in the toolbar. All blogs and their corresponding posts will then be deleted from the app's SQLite database.

![Screenshot of app with all blogs deleted](_static/xamarin-tutorial-5.png)

## Explore the code

The following sections will walk you through the code in the sample project that reads, creates, updates, and deletes data from a SQLite database using EF Core with Xamarin.Forms.

It is assumed that you are familiar with the Xamarin.Forms topics of [displaying data](/xamarin/xamarin-forms/app-fundamentals/data-binding/) and [navigating between pages](/xamarin/xamarin-forms/app-fundamentals/navigation/).

## Entity Framework Core NuGet packages

To create Xamarin.Forms apps with EF Core, you install the package for the EF Core database provider(s) you want to target into all of the projects in the Xamarin.Forms solution. This tutorial uses the SQLite provider.

The following NuGet package is needed in each of the projects in the Xamarin.Forms solution.

* `Microsoft.EntityFrameworkCore.Sqlite`

## Model classes

Each table in the SQLite database accessed through EF Core is modeled in a class. In this sample, two classes are used: `Blog` and `Post` which can be found in the `Models` folder.

The model classes are composed only of properties, which model columns in the database.

* **Blog.cs**

[!code-csharp[](../../../samples/core/Xamarin/EFGetStarted/Models/Blog.cs)]

* The `Posts` property defines a parent-child relationship between `Blog` and `Post`.

* **Post.cs**

[!code-csharp[](../../../samples/core/Xamarin/EFGetStarted/Models/Post.cs)]

* The `BlogId` and `Blog` properties relate back to the parent `Blog` object for the instance of the `Post`.

## Data context

The `BloggingContext` class is located in the `Services` folder and inherits from the EF Core `DbContext` class. A `DbContext` is used to group together database queries and changes.

[!code-csharp[](../../../samples/core/Xamarin/EFGetStarted/Services/BloggingContext.cs)]

* Both properties in this class of type `DbSet` are used to operate on the underlying tables representing Blogs and Posts.
* The `SQLitePCL.Batteries_V2.Init()` is needed in the constructor to initiate SQLite on iOS.
* The `OnConfiguring` function sets up the location of the SQLite database on the physical device.

## Create, read, update & delete

The following are some instances in the app where EF Core is used to access SQLite.

### Read

* Return all records.
* The `OnAppearing` function of `BlogsPage.xaml.cs` returns all `Blog` records and stores them into a `List` variable.

```csharp
using (var blogContext = new BloggingContext())
{
var theBlogs = blogContext.Blogs.ToList();
}
```

* Return specific records.
* The `OnAppearing` function of `PostsPage.xaml.cs` returns `Post` records that contain a specific `BlogId`.

```csharp
using (var blogContext = new BloggingContext())
{
var postList = blogContext.Posts
.Where(p => p.BlogId == BlogId)
.ToList();
}
```

### Create

* Insert a new record.
* The `Save_Clicked` function of `AddBlogPage.xaml.cs` inserts a new `Blog` object into the SQLite database.

```csharp
var blog = new Blog { Url = blogUrl.Text };

using (var blogContext = new BloggingContext())
{
blogContext.Add(blog);

await blogContext.SaveChangesAsync();
}
```

### Update

* Update an existing record.
* The `Save_Clicked` function of `AddPostPage.xaml.cs` updates an existing `Blog` object with a new `Post`.

```csharp
var newPost = new Post
{
BlogId = BlogId,
Content = postCell.Text,
Title = titleCell.Text
};

using (var blogContext = new BloggingContext())
{
var blog = await blogContext
.Blogs
.FirstAsync(b => b.BlogId == BlogId);

blog.Posts.Add(newPost);

await blogContext.SaveChangesAsync();
}
```

### Delete

* Delete all records with cascade to child records.
* The `DeleteAll_Clicked` function of `BlogsPage.xaml.cs` deletes all the `Blog` records in the SQLite database and cascades the deletes to all of the `Blog` child `Post` records.

```csharp
using (var blogContext = new BloggingContext())
{
blogContext.RemoveRange(blogContext.Blogs);

await blogContext.SaveChangesAsync();
}
```

## Next steps

In this getting started you have learned how to use a Xamarin.Forms application to access a SQLite database using Entity Framework Core.

Other Entity Framework Core topics of interest to Xamarin developers:

* [Configuring a `DbContext`](xref:core/miscellaneous/configuring-dbcontext)
* Learn more about [LINQ query expressions](/dotnet/csharp/programming-guide/concepts/linq/basic-linq-query-operations)
* [Configure your model](xref:core/modeling/index) to specify things like [required](xref:core/modeling/entity-properties#required-and-optional-properties) and [maximum length](xref:core/modeling/entity-properties#maximum-length)
2 changes: 2 additions & 0 deletions entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
href: core/get-started/install/index.md
- name: ASP.NET Core tutorial >>
href: /aspnet/core/data/ef-rp/intro
- name: Xamarin tutorial
href: core/get-started/xamarin.md
- name: Fundamentals
items:
- name: Connection strings
Expand Down
19 changes: 19 additions & 0 deletions samples/core/Xamarin/EFGetStarted.Android/Assets/AboutAssets.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".

These files will be deployed with your package and will be accessible using Android's
AssetManager, like this:

public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);

InputStream input = Assets.Open ("my_asset.txt");
}
}

Additionally, some Android functions will automatically load asset files:

Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
106 changes: 106 additions & 0 deletions samples/core/Xamarin/EFGetStarted.Android/EFGetStarted.Android.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Xamarin require old-style projects like this?

<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8969C333-0071-4893-91BE-18050B0343C9}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
<OutputType>Library</OutputType>
<RootNamespace>EFGetStarted.Droid</RootNamespace>
<AssemblyName>EFGetStarted.Android</AssemblyName>
<Deterministic>True</Deterministic>
<AndroidApplication>True</AndroidApplication>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<AndroidUseAapt2>true</AndroidUseAapt2>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Forms" Version="4.7.0.1080" />
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite">
<Version>3.1.5</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>12.0.3</Version>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore">
<Version>3.1.5</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Tabbar.xml" />
<AndroidResource Include="Resources\layout\Toolbar.xml" />
<AndroidResource Include="Resources\values\styles.xml" />
<AndroidResource Include="Resources\values\colors.xml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml" />
<AndroidResource Include="Resources\mipmap-hdpi\icon.png" />
<AndroidResource Include="Resources\mipmap-hdpi\launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-mdpi\icon.png" />
<AndroidResource Include="Resources\mipmap-mdpi\launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png" />
<AndroidResource Include="Resources\mipmap-xhdpi\launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png" />
<AndroidResource Include="Resources\mipmap-xxhdpi\launcher_foreground.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png" />
<AndroidResource Include="Resources\mipmap-xxxhdpi\launcher_foreground.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\drawable\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EFGetStarted\EFGetStarted.csproj">
<Project>{E5DCDF9D-4AF4-4570-A9B6-D7C78DB2096F}</Project>
<Name>EFGetStarted</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>
33 changes: 33 additions & 0 deletions samples/core/Xamarin/EFGetStarted.Android/MainActivity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;

using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

namespace EFGetStarted.Droid
{
[Activity(Label = "EFGetStarted", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;

base.OnCreate(savedInstanceState);

Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.microsoft.efgetstarted">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:label="EFGetStarted.Android"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
Loading