Unable to generate database table using Entity Framework Code First approach - ef-code-first

Written the following simple code to learn about Entity Framework Code First approach. But, I am unable to make it work.
Not getting any error as well. When verified the generated .mdf file, no record found.
Unable to identify the problem even while debugging the code. Can anyone please suggest me where I am doing wrong!
Below is my code.
Below is the Person class
namespace EFCF
{
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Below is the context class
namespace EFCF
{
public class Context : DbContext
{
public DbSet<Person> Persons { get; set; }
}
}
Below is the test program written in Console Application.
namespace TestEFCF
{
class Program
{
static void Main(string[] args)
{
//Insert person record
using (var context = new Context())
{
context.Database.CreateIfNotExists();
Person person = new Person
{
PersonId = 1001,
FirstName = "Ashok",
LastName = "Kumar"
};
context.Persons.Add(person);
}
//Get person record
using (Context context = new Context())
{
var people = context.Persons;
foreach (var person in people)
{
Console.WriteLine(person.PersonId + "\t" + person.FirstName + "\t" + person.LastName);
}
}
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
}

You have to first run Add-Migration <YourMigrationName> command (its equivalent to generating the migration script in DB first approach)from Package Manager Console in Visual Studio. Then run Update-Database command (it is equivalent to running the migration script in DB first approach)to apply the migration.
You can refer this page for details information.
Note: Remove the unnecessary code from C# code to generate the database.

Small mistake in my previous code.
No need to enable migrations for this particular situation. Just add context.SaveChanges() command at the right place as shown below.
Below is the complete code.
//Insert person record
using (var context = new Context())
{
context.Database.CreateIfNotExists();
Person person = new Person
{
FirstName = "Ashok",
LastName = "Kumar"
};
context.Persons.Add(person);
context.SaveChanges();
}

Related

EF Core with CosmosDB: OwnsOne and OwnsMany throw NullReferenceException

I'm working on a new project that uses CosmosDB and Entity Framework Core (via the Microsoft.EntityFrameworkCore.Cosmos NuGet package, version 5.0.7; the project itself is .NET Core 5). I'm new to both, and running into an issue I can't sort out.
In short, I need to save a complex object to the database. It's a big model that will have multiple collections of classes underneath it, each with their own properties and some with collections underneath them as well. I'm trying to configure EF with OwnsOne and OwnsMany to store these child objects underneath the top-level one. The code compiles, and will save to the database so long as all the owned objects are left empty. But whenever I put anything into an owned object, either with OwnsOne or OwnsMany, I get a pair of NullReferenceExceptions.
I've tried to strip my code down to the very basics. Here's how it currently looks.
Owner and owned classes:
public class Questionnaire
{
// Constructors
private Questionnaire() { }
public Questionnaire(Guid id)
{
Test = "Test property.";
TV = new TestQ();
Id = id;
}
public Guid Id { get; set; }
public string Test { get; set; }
public TestQ TV { get; set; }
// Public Methods
public void AddForm(Form f)
{
// not currently using this method
//Forms.Add(f);
}
}
public class TestQ
{
public TestQ()
{
TestValue = "test ownsone value";
}
public string TestValue { get; set; }
}
DbContext:
public class QuestionnaireDbContext : DbContext
{
public DbSet<Questionnaire> Questionnaires { get; set; }
public QuestionnaireDbContext(DbContextOptions<QuestionnaireDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultContainer(nameof(Questionnaires));
modelBuilder.Entity<Questionnaire>().HasKey(q => q.Id);
modelBuilder.Entity<Questionnaire>().OwnsOne(q => q.TV);
}
}
And the code from the service that calls the dbContext (note that this is based on a generic service that I didn't set up originally). The actual exceptions are thrown here.
public virtual TEntity Add(TEntity entity)
{
_context.Entry(entity).State = EntityState.Added;
_context.SaveChanges();
return entity;
}
Ultimately I need this to work with OwnsMany and a collection, but I figured it might be simpler to get it working with OwnsOne first. The key thing to note here is that if I comment out the line
TV = new TestQ();
in the Questionnaire class, the model persists correctly into CosmosDB. It's only when I actually instantiate an owned entity that I get the NullReferenceExceptions.
Any advice would be much appreciated! Thank you!
Well, I'm not sure why this is the case, but the issue turned out to be with how we were adding the document. Using this generic code:
public virtual async Task<TEntity> Add(TEntity entity)
{
_context.Entry(entity).State = EntityState.Added;
await _context.SaveChanges();
return entity;
}
was the issue. It works just fine if I use the actual QuestionnaireDbContext class like so:
context.Add(questionnaire);
await context.SaveChangesAsync();

Dynamically generate a class in C# for SQLite

I am using Xamarin.Forms .Net Standard 1.4 library and the SQLite nuget.
I create classes for my database tables/records as follow:
namespace MyNamespace
{
[Table("my_table")]
public class MyRecord
{
[PrimaryKey, AutoIncrement, Column("_id")]
public int ID { get; set; } = -1;
[Unique, NotNull, Column("GUID")]
public Guid GUID { get; set; } = Guid.NewGuid();
public string Field1 { get; set; }
public string Field1 { get; set; }
}
}
And I can create/insert the table/records with
{
SQLiteConnection conn = new SQLiteConnection(db_file);
conn.CreateTable<MyRecord>();
var record = new MyRecord {
Field1 = "test",
Field2 = "test"
};
conn.Insert(record);
conn.Dispose();
}
I find myself in the situation where one table does not have known columns at compile time, so I can't create a class to describe it. Is there an easy way to dynamically generate a class?
Suppose that during runtime I need to create a table with the following columns (all text) "NewField1", "NewField2". I realize I could generate the SQL command to data. But I lose the convenience of the wrapper from SQLite.
I would like to dynamically create a class and add the Properties as needed so I could still use CreateTable<> and Insert(), etc. Is this possible? Would it be efficient? Or am I better off just using a Dictionary and creating SQL commands.

query soft deleted records in an Azure mobile app easy table

I have a Azure mobile Easy Table Xamarin App that is a bunch of lists, reminders for myself. It works fine to add, update and delete. I want to be able to get a list of soft deleted items so I can undelete some to add them back into a list without retyping them. I cannot figure out how to do this. I see in Google searches an IncludeDeleted attribute but it does not seem to apply to the IMobileServiceSyncTable table I am using. Here is the code, but it retrieves zero records. If I run it in LinqPad 5 I get all the soft deleted records.
public async Task<IEnumerable<ListData>> GetDeletedItemsAsync()
{
await InitializeClient();
await SyncItems();
try
{
IEnumerable<ListData> items = await listdata
.Where(listdata => listdata.Deleted == true )
.ToEnumerableAsync();
return new ObservableCollection<ListData>(items);
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.Message);
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
}
return null;
}
Here is the Class:
public class ListData
{
public string id { get; set; }
[JsonProperty(PropertyName = "listname")]
public string ListName { get; set; }
[JsonProperty(PropertyName = "itemdata")]
public string ItemData { get; set; }
[JsonProperty(PropertyName = "itemdetail")]
public string ItemDetail { get; set; }
[JsonProperty(PropertyName = "deleted")]
public Boolean Deleted { get; set; }
// *** Enable Optimistic Concurrency *** //
[Version]
public string Version { get; set; }
}
What am I missing? Thanks.
Per my understanding, you could try to change your SyncItems method as follows:
private async Task SyncItems()
{
var queryName = $"incsync:s:{typeof(ListData).Name}";
var query = listDataTable.CreateQuery().IncludeDeleted();
await listDataTable.PullAsync(queryName, query);
}
And you could use fiddler to capture the network traces when invoking the above method, then you could check the response and find whether you could retrieve the deleted items.
Then you could leverage DB Browser for SQLite or any other tool to check your local SQLite database and verify your table records to narrow this issue.
The way to do this is to go directly to the server using an IMobileServiceTable object. It is pretty simple. You can then use the IncludeDeleted directive on the query. Case solved.

Windows Phone sqlite select all

I have a query which simply does, in a table named "CUSTOMER" a select all.
This is my Table:
public class CUSTOMER : Extension.Shared
{
[PrimaryKey, Indexed]
public Guid ID { get; set; }
[Indexed]
public string FULL_NAME { get; set; }
public string PHONE_NO { get; set; }
//public string PIVA_CF { get; set; }
public DateTime? MODIFIED_ON { get; set; }
And this is the query which gives me the problem
public List<CUSTOMER> SelectAll()
{
SQLiteConnection conn = new SQLiteConnection(DatabasePath());
return conn.Query<CUSTOMER>("SELECT * FROM CUSTOMER");
}
Every times i run this operation, the query returns an error from SQLite.cs file:
if (r != SQLite3.Result.OK)
{
throw SQLiteException.New (r, String.Format ("Could not open database file: {0} ({1})", DatabasePath, r));
}
If the size can be a useful, this table has nearly 50000 records.
I have the same problem in a couple of tables with 100000 or 80000 records.
No problems with other Tables, no problem with other queries.
I can say this because since I thought the table was badly saved, I installed again and again the table, but I noticed that from the same page i can call this query without any problem, for all tables:
public List<CUSTOMER> SelectByFilter(string Filter)
{
SQLiteConnection conn = new SQLiteConnection(DatabasePath());
return conn.Query<CUSTOMER>(string.Format("SELECT * FROM CUSTOMER WHERE FULL_NAME LIKE '{0}%'", Filter));
}
I don't really know where can this error came from. I don't know any size's restriction on Sqlite3. Any help will be appreciated.
This error tells that it cannot find the database at the path given check with isolated storage tool that the database exist in that place also check you are referencing the correct path to database file in your DatabasePAth() method or else try this
public List<CUSTOMER> SelectByFilter(string Filter)
{
string dbpath = System.IO.Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "yourdatabsefilename.db");
//database is in home directory not in any subfolders. then only this code will work
SQLiteConnection conn = new SQLiteConnection(dbpath);
return conn.Query<CUSTOMER>(string.Format("SELECT * FROM CUSTOMER WHERE FULL_NAME LIKE '{0}%'", Filter));
}

Creating an EF CodeFirst DbContext using Roslyn

Just a little idea I'm playing with, not sure if it's viable or has much of a use.
I'm trying to generate a very basic EF Code First database using the Roslyn CTP.
Code:
var scriptEngine = new ScriptEngine(new[] { "System", "System.Core", typeof(DbContext).Assembly.Location });
var session = Roslyn.Scripting.Session.Create();
var t = scriptEngine.CompileSubmission<DbContext>(#"
using System.Data.Entity;
public class Car {
public int Id {get; set;}
public string Name {get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars {get; set; }
}
new Context();
", session);
t.Execute();
When executed I get the following exception
Exception:
The type 'Submission#0+Car' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject.
Looking through the list of possible issues, I'm guessing that Roslyn is making a nested class as part of the code gen. This makes sense otherwise the "new Context();" call would need to be wrapped into a class/method of some sort. I could emit an assembly, which would confirm the above but likely wouldn't have any clues on how to write it correctly.
I also went down the route of Syntax.ClassDeclaration, but ended up with a few hundred lines of code just to make a class with 1 property and no obvious way how to instantiate that class.
Question
Is there an easy way to create a class in Roslyn that is publicly accessible (eg not nested in another class)?
You can use Roslyn to create actual DLL library that contains your type based on your source code and then use that from your script:
var classCode = #"
using System.Data.Entity;
public class Car {
public int Id { get; set; }
public string Name { get; set; }
}
public class Context : DbContext {
public DbSet<Car> Cars { get; set; }
}";
var syntaxTree = SyntaxTree.ParseCompilationUnit(classCode);
var compilation = Compilation.Create(
"car",
new CompilationOptions(assemblyKind: AssemblyKind.DynamicallyLinkedLibrary))
.AddReferences(
new AssemblyFileReference(typeof(object).Assembly.Location), // mscorlib
new AssemblyFileReference(typeof(Uri).Assembly.Location), // System
new AssemblyFileReference(typeof(IOrderedQueryable<>).Assembly.Location), // System.Data
new AssemblyFileReference(typeof(DbContext).Assembly.Location) // EntityFramework
)
.AddSyntaxTrees(syntaxTree);
var dllPath = "car.dll";
using (var stream = File.OpenWrite(dllPath))
{
compilation.Emit(stream);
}
var code = #"new Context();";
var scriptEngine = new ScriptEngine(new[] { new FileInfo(dllPath).FullName, "EntityFramework" });
var context = scriptEngine.Execute<DbContext>(code);

Resources