This is my first time using EF in VS2012 as I have been using 2010 for up until now. I have added the entity framework model and it adds 2 files with the extension .tt which I am sure was not present in VS2010. Under one of these it generates partial classes to match the entities. However I already have these partial classes in another manually created folder called Entites under the root of my app. This causes an issue on build as they conflict...
How do I either either stop them autogenerating or how do I make them play nice with my manually created partial classes? It is incredibly annoying that VS2012 does this without asking as it breaks my code!
Example of Auto Generated class
namespace StatisticsServer
{
using System;
using System.Collections.Generic;
public partial class Statistic
{
public int StatID { get; set; }
public int CategoryID { get; set; }
public int FranchiseID { get; set; }
public double StatValue { get; set; }
}
}
Example of Manually created class
namespace StatisticsServer.Entities
{
public partial class Statistic
{
public static List<Statistic> GetStatisticsSet(int categoryID)
{
List<Statistic> statSet = new List<Statistic>();
using (var context = new StatisticsTestEntities())
{
statSet = (from s in context.Statistics where s.CategoryID == categoryID select s).ToList();
}
return statSet;
}
}
}
Make sure that your manually created classes are in the same namespace as the auto-generated ones.
Otherwise the two classes will be seen as separate partial classes, and if you use both namespaces in the same calling class it cannot determine which class you mean.
So for example in your case you might have:
using StatisticsServer;
using StatisticsServer.Entities;
When you then declare an object of the type Statistic in that class the build will fail because the Statistic class exists in both namespaces.
Related
I am using the SQLite.Net-PCL library to manage the SQLite database in my UWP app. The documentation says that calling CreateTableAsync is able to add columns to the table if a properly is added to the data model. However, when I add a property, the application throws an exception that says the table does not have a column named . This means that the new column was not created automatically. I am calling CreateTableAsync in the constructor of the class that manages database calls for the table with a repository design pattern.
I think you missed decorations [PrimaryKey, AutoIncrement] for your class model. Please check the following DataTemple class.
public class DataTemple
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; } //primary key
public string Name { get; set; }
public string Age { get; set; }
}
For more detail you could also refer this sample.
I pulled out all of my CreateTableAsync calls from the repository class constructors and moved them into separate Init Tasks so I can properly await. Now I can add columns to any table without problems.
I have two code first entities, Package and PackageEntry that I am having trouble setting up in EF Core.
I am trying to achieve the following with the code first entities and the Fluent API:
A Package can contain any number of PackageEntries
Each PackageEntry has a reference to a single Package entity (a different instance of a package, unrelated to the parent Package reference that contains the collection of PackageEntries)
The two entities:
public class Package{
public Package()
{
_packageEntries = new List<PackageEntry>();
}
//trimmed other properties
private readonly List<PackageEntry> _packageEntries;
[NotMapped]
public IReadOnlyCollection<PackageEntry> PackageEntries => _packageEntries.ToList().AsReadOnly();
}
and
public class PackageEntry
{
public int DisplayOrder { get; set; }
public int PackageID { get; set; }
public Package Package { get; set; }
public int Quantity { get; set; }
public Package ParentPackage { get; set; }
public int ParentPackageID { get; set; }
}
What I currently have using the Fluent API, which is not working is:
modelBuilder.Entity<Package>().HasMany(x => x.PackageEntries).WithOne();
modelBuilder.Entity<PackageEntry>().HasOne(x => x.Package).WithOne().HasForeignKey(typeof(PackageEntry), "PackageID");
It isn't throwing errors, but what I am seeing is that when a PackageEntry is added to a package, it is not getting saved when calling SaveChanges on the context.
Am I doing something wrong with the Fluent API or something else?
EDIT
I had missed adding the top level package to the context, once that was done the package entry that gets added to it is being saved. I would still appreciate comments on the Fluent API setup and any best practices.
From the PackageEntry entity, I need to know both the Parent Package and the contained Package which will be separate references to the same type. I can't seem to set this up with the Fluent API, when the Parent Package is loaded via EF it doesn't contain any PackageEntry objects, even if their ParentPackageID is set correctly.
Upon some offline advice from an EF expert, I have worked around this issue by removing the navigation property for PackageEntry.Package and simply manually handle the foreign key for that package entity.
Once I did that, now when the Parent Package entity is loaded, it properly loads the children PackageEntries.
So, the PackageEntry class now looks like this:
public class PackageEntry
{
public int DisplayOrder { get; set; }
public int PackageID { get; set; }
//public Package Package { get; set; } //Handle manually
public int Quantity { get; set; }
public Package ParentPackage { get; set; }
public int ParentPackageID { get; set; }
}
And the Fluent API code:
navigation = builder.Metadata.FindNavigation(nameof(Package.PackageEntries));
//EF access the PackageEntries collection property through its backing field
navigation.SetPropertyAccessMode(PropertyAccessMode.Field);
modelBuilder.Entity<Package>().HasMany(x => x.PackageEntries)
.WithOne("ParentPackage")
.HasForeignKey(nameof(PackageEntry.ParentPackageID))
.IsRequired()
.OnDelete(DeleteBehavior.Restrict);
Your Package.PackageEntries collection is marked [NotMapped], and it does not have a setter. No matter what, EntityFramework is not going to pick that up.
I've never tried using an IReadonlyCollection<T> with EntityFramework, but I would imagine that EF won't like that either.
Your first try should be to remove the attribute and arrange the property like this:
public virtual IReadOnlyCollection<PackageEntry> PackageEntries {
get {
return _packageEntries.ToList().AsReadonly();
}
protected internal set {
_packageEntries = value;
}
}
Granted, that would require you to remove the readonly from the private member variable.
That being said, I'm not sure if EF has an internal list that it eventually assigns to the property, but I would imagine that it would just call the Add() method on the collection (which is why your properties must be ICollection<T> instead of IEnumerable<T>.
Therefore, if that is all still not working, you should make _packageEntries protected internal and use that as your EF collection. Then you can only publicly expose your PackageEntries as you are doing now.
Using Microsoft.EntityFrameworkCore.SQLite, I'm attempting to create a code level creation of a database, and add a simple row to a table. I get the error, SQLite error: no such table Jumplists.
From last to first, here are the classes
using JumpList_To_Clipboard.Data.Tables;
using Microsoft.EntityFrameworkCore;
namespace JumpList_To_Clipboard.Data
{
public class DataSQLite : IData
{
public const string DATABASE = "data.sqlite";
public DataSQLite()
{
using (var db = new SQLiteDbContext(DATABASE))
{
// Ensure database is created with all changes to tables applied
db.Database.Migrate();
db.JumpLists.Add(new JumpList { Name = "Default" });
db.SaveChanges(); // Exception thrown here
}
}
}
}
The DbContext class
using JumpList_To_Clipboard.Data.Tables;
using Microsoft.EntityFrameworkCore;
namespace JumpList_To_Clipboard.Data
{
class SQLiteDbContext : DbContext
{
readonly string db_path;
public DbSet<JumpList> JumpLists { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Item> Items { get; set; }
public SQLiteDbContext(string database) : base()
{
db_path = database;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(string.Format("Data Source={0}", db_path));
}
}
}
The JumpList class
using System.Collections.Generic;
namespace JumpList_To_Clipboard.Data.Tables
{
public class JumpList
{
public int JumpListId { get; set; }
public string Name { get; set; }
public List<Group> Groups { get; set; }
public List<Item> Items { get; set; }
}
}
The other two classes aren't worth repeating here, and don't give errors.
When I use the firefox sqlite extension to look at the data.sqlite file, none of my three tables are listed.
The command db.DataBase.Migrate says it
Applies any pending migrations for the context to the database.
What are pending migrations? I can't seem to find any documentation anywhere on these.
I'm combining examples from:
https://learn.microsoft.com/en-us/ef/core/get-started/netcore/new-db-sqlite
https://blogs.msdn.microsoft.com/dotnet/2016/09/29/implementing-seeding-custom-conventions-and-interceptors-in-ef-core-1-0/
Edit: If I replace db.Database.Migrate(); with db.Database.EnsureCreated(); it works. From the documentation, Migrate() is the same, but lets you create updates to the table structures, where EnsureCreated() does not. I'm confused.
So,
Microsoft has a serious issue making decent documentation, but I did find a site that has somewhat dated documentation for Learning Entity Framework Core, specifically migrations which is in the link.
At the top, it mentions,
If you have Visual Studio, you can use the Package Manager Console (PMC) to manage migrations.
Which led to the Package Manager Console page which states right at the top, that you need to have:
If you want to use the Package Manager Console to execute migrations command, you need to ensure that the latest version of Microsoft.EntityFrameworkCore.Tools is added to your project.json file.
The problem is, there is no project.json file anywhere in my project (or solution). After some searching, I found that via NuGet, to add Microsoft.EntityFrameworkCore.Tools
Then via Tools > NuGet Package Manager > Package Manager Console I was able to run the add-migration InitialDatabases command. The last part InitialDatabases is the name of the class it creates for you, and sticks in a folder called Migrations at the base of the project.
Now when:
context.Database.Migrate();
is run, all is well!
Try this (worked for me in a project a few months ago, i don't remember why):
public virtual DbSet<JumpList> JumpLists { get; set; }
public virtual DbSet<Group> Groups { get; set; }
public virtual DbSet<Item> Items { get; set; }
Also i had to use LONG instead of INT for classes ID because sqlite uses LONG as default for table ID, so after when you do a CRUD operation it fails because it can't compare/convert/cast LONG(64) to INT(32).
i'm trying to unit test my presenter in MVP application. here is my view interface which i'm trying to mock out using NSubstitude:
public interface ICategoriesView : IBaseViewInterface
{
string CategoryName { get; }
long CategorId { get; }
long CategoryParent { get; }
IEnumerable<EntityObject> CategoryDataSource { set; }
}
here is my unit test class. i'm using NUnit framework:
[TestFixture]
public class CategoriesTests
{
[Test(Description="this is used for testing the behavior of presenter if we pass empty name.")]
public void Add_EmptyName_Fails()
{
var _view = NSubstitute.Substitute.For<ICategoriesView>();
//now here i'm supposed to get something like _view.CategoryId.Returns(2) but i don't!
//the error message says that _view.CategoryId doesn't have an extension method
//named Returns. and it's true since intellisence doesn't list it after period
}
}
i added set modifer to the view interface and it didn't work. so what is wrong?
actually i forgot to add a using NSubstitude on top of my test class.
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);