How would I use a seperate Models only project with PetaPoco? - c#

I currently have the following in one solution:
Core Project (data access, biz logic, petapoco for data access, the plumbing, etc)
Models Project (just models and petapoco decorations for just attributes)
Web Project (MVC project for presentation
I want to have my Models and Core seperate, but I can't have PetaPoco.cs in both places. How would I seperate it and still be able to decorate the POCOs in my Models project with PetaPoco attributes?
I don't want the Models project to have a dependency on the Core project.
I did create this seperate class to be only in the Models project so I could decorate the POCOs, but the attributes are not being picked up properly by the Core PetaPoco project. It relies on PocoData too much.
Suggestions?
// Poco's marked [Explicit] require all column properties to be marked
[AttributeUsage(AttributeTargets.Class)]
public class ExplicitColumnsAttribute : Attribute
{
}
// For non-explicit pocos, causes a property to be ignored
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreAttribute : Attribute
{
}
// For explicit pocos, marks property as a column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute
{
public ColumnAttribute() { }
public ColumnAttribute(string name) { Name = name; }
public string Name { get; set; }
}
// For explicit pocos, marks property as a result column and optionally supplies column name
[AttributeUsage(AttributeTargets.Property)]
public class ResultColumnAttribute : ColumnAttribute
{
public ResultColumnAttribute() { }
public ResultColumnAttribute(string name) : base(name) { }
}
// Specify the table name of a poco
[AttributeUsage(AttributeTargets.Class)]
public class TableNameAttribute : Attribute
{
public TableNameAttribute(string tableName)
{
Value = tableName;
}
public string Value { get; private set; }
}
// Specific the primary key of a poco class (and optional sequence name for Oracle)
[AttributeUsage(AttributeTargets.Class)]
public class PrimaryKeyAttribute : Attribute
{
public PrimaryKeyAttribute(string primaryKey)
{
Value = primaryKey;
autoIncrement = true;
}
public string Value { get; private set; }
public string sequenceName { get; set; }
public bool autoIncrement { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class AutoJoinAttribute : Attribute
{
public AutoJoinAttribute() { }
}

I think one obvious solution, though, I'm not sure it's that much better, is to move PetaPoco to its own project and then reference that in both your Core and Models projects. Your models still have an external dependency, though, just not the whole Core assembly.
One other alternative would be to have your decorated models in your Core project for internal use, and then have a set of undecorated classes in your Models assembly. You could use an auto-mapping component to map between the two easily. So basically you would use PetaPoco to fetch data into your internal model, and then map that over to your 'external' model which is just bare classes with no dependencies.
Of course, that sounds like a lot of extra work. I guess it all hinges on how critical it is that your Model assembly have no other dependencies.

Related

Invalid column name 'Discriminator' when having a derived class

I have a ASP.NET MVC + EF web application, but I get an error when trying to query a list of Product using LINQ:
Invalid column name 'Discriminator'. Invalid column name 'NewProductPhoto'
This happened after I added a derived class from one of my entities.
My entity class:
[Table("Product")]
public partial class Product
{
public Product()
{
ProductPhotos = new HashSet<ProductPhoto>();
SalesOrderItems = new HashSet<SalesOrderItem>();
}
// more attributes here
}
My new derived class:
public class ProductEx : Product
{
public byte[] NewProductPhoto { get; set; }
}
I understand that EF tries to distinguish between Product and ProductEx but the point is I have no intention to add ProductEx to EF model.
I don't know why it considers ProductEx as part of database model.
How can I tell EF to not consider ProductEx as database model.
I found that the same way I can exclude a property from entity framework persistent, I can exclude my ProductEx class from entity framework modeling.
The attribute [NotMapped] does the trick.
[NotMapped]
public class ProductEx : Product
{
public byte[] NewProductPhoto { get; set; }
}
I still don't understand why EF even considers my derived class for persistence.

asp.net class library that talks to ef and customizable

I'm trying to make a class library that contains only the core logic of may app.
I've seen many tutorials that do this but they include the EF core inside that library. What I want to do is put only all the logic such, adding a category if it doesn't exist yet by passing a string.
Here 's what I want to do
Create a class library in separated project.
Add a class called SomeNameManager - [contains all the methods I want]
Create models to be modified by this manager but I don't want this to be the class directly used as my entity. I just want this to be the base class of my entity for customization. for example if I have to add a new propery, I'd just change the entity in my main app. not in the library.
The DbContext is in my main app only. Which means all of my classes and lists that used in my library will be just in the memory.
Here's what I got so far
// class library
public interface IBook{
// some properties here
ICollection<ICategory> Categories { get; set; }
// some more properties...
}
public interface ICategory{
// some properties here
ICollection<IBook> Books { get; set; }
// some more properties...
}
public class Book : IBook {
// implementations...
}
public class Category : ICategory {
// implementations
}
public class BookManager {
public void CreateBook(Book book) {
// some logic
// I'm not sure if I would pass Book or IBook
}
public void AddCategories(List<Category> categories) {
// some logic
// I'm not sure if I would pass Category or ICategory
}
}
// my main app
public class BookInfo {
// some props...
}
public class BookCategory {
// some props...
}
public class MyDB : DbContext{
public DbSet<BookInfo> BookInformations {get; set;}
public DbSet<BookCategory> BookCategories {get; set;}
}
The problems
The table name in my database is Book. I don't want to use fluent API just to rename this.
I have new column it both database called Discriminator. What is that? I do I remove that?
Categories isn't binding to Book.Categories. It's empty but it inserts to the database.
Additional Question
Am I doing this right?
Is it a bad idea? Please enlighten me. I'm not beginner but I haven't been in the real development team.
1 .The table name in my database is Book. I don't want to use fluent API just to rename this.
To give a class a different table name you can do this with the fluent API but since you don't want to do that you can use the [Table] attribute for this:
[Table("BookTableName")]
public class Book : IBook {
// implementations...
}
2. I have new column it both database called Discriminator. What is that? I do I remove that?
A discriminator column is used to identify which type each row represents.
See the docs

Derived POCOs referencing same table - strange naming issues

I have a "base" entity with some properties that's being used by a bunch of other stuff (repository patterns, queues, etc) in some shared libraries. Mapped to a pluralized table.
I need to add a property to it for my specific implementation, and I want to reuse all the rest of the normal behaviors.
I derive a class:
public interface IItem {
[Key]
Guid Id { get; set; }
string Name { get; set; }
}
public class Item : IItem {
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
}
public interface IExtended {
bool IsExtended { get; set; }
}
[Table("Items")] // <-- my nemesis
public class ExtendedItem : Item, IExtended {
[Column("_Extended")]
public bool IsExtended { get; set; }
}
I set up the code-first context:
public class MyContext : DbContext {
public MyContext(string connectionString) : base(connectionString) {
// manually creating the tables, no migrations
Database.SetInitializer<EfQueueContext>(null);
}
public DbSet<Item> Items { get; set; }
}
Without DataAnnotation [Table] I get exception "Invalid column name 'Discriminator'" -- okay, weird but makes sense
With [NotMapped] I get exception "The entity type ExtendedItem is not part of the model for the current context" -- okay, makes sense
With annotation [Table("Item"] I get exception "table 'dbo.Item' doesn't exist" -- okay, duh forgot it pluralized original
With annotation [Table("Items")] I get exception "table 'dbo.Items1' doesn't exist" -- what??? where did the 1 suffix come from?
Even creating a brand-new DbContext that only refers to ExtendedItem and not Item still adds the '1' (update - I didn't actually create a clean instance; see comment on answer)
The problem is EF deduce you want to create a Table per Type (TPT) when you apply the Table atribute on the subclasses to specify the mapped table name. In your case you are trying to rename the table related with theExtendedItem entity, but you are using the same name of the root table, that's way EF is creating two tables one called Items1 (because you already use the Items name in the inheriting entity) related to the Item entity and another called Items related to the ExtentedItem entity
If you want to create a Table per Hierarchy (TPH) and you want to rename the root table, then you need to apply the [Table("Items")] data annotation on the root entity (Item) and all entities that inherit from it.

How to define collections in a common interface to fit EntityFrameworks auto generated collections?

I'm creating a multi platform application (.NET 4.5/WPF, Windows Phone 8, SilverLight 5) using the MVVM pattern. My ViewModel project is a PCL (portable class library) shared/used by all platform specific Views. In my Windows application I want to access the database directly via Entity Framework 6.
I've two projects representing the data layer:
Data.Common: Includes entity/repository/unitofwork interfaces. They are used in my ViewModels.
Data.EF: Includes EntityFramework "stuff" (edmx file = auto generated DbContext and entity classes)
I will show my problem with my IUser interface:
// Data.Common.IUser
public interface IUser : IEntity
{
// Primitives representing table columns.
// They will be implemented fine by EF's auto generated classes.
int ID { get; set;}
string UserName { get; set; }
// Collections representing table relations.
// They are my problem because EF's generated classes don't fit to this.
ICollection<IUserApplication> UserApplications { get; set; }
}
To implement my interface I created a partial class for each EF auto generated entity class in Data.EF project:
// Data.EF.User, my file
public partial class User : IUser
{
// fields are implemented in other part
}
// Data.EF.User, file created by EntityFramework
public partial class User
{
public User()
{
this.UserApplications = new HashSet<UserApplication>();
}
public int ID { get; set; } // fine, this implements IUser.ID
public string UserName { get; set; } // fine, this implements IUser.UserName
// And here's the other part of my problem:
// This collection is of type ICollection<UserApplication> but UserApplication is not known in my ViewModel, only IUserApplication.
public virtual ICollection<UserApplication> UserApplications { get; set; }
}
How should the collections (like ICollection<IUserApplication>) representing the data table relations in my interfaces look like? It's not possible to simply cast a Collection<IUserApplication> to a Collection<UserApplication> so can this be achieved in any other way?

EntityFramework extend base model in different DLL

I have a DLL with a base model using code first EF 4.3.
What i want is to extend certain models in that dll with additional fields.
for example in BaseModel.DLL
namespace BaseModel
{
public class Account
{
public Id { get;set;}
public string Name {get;set;}
}
}
in a referencing project i want to extend the Account model (and DB table):
public class Account : BaseModel.Account
{
public string SomeAdditionalInfo { get;set;}
}
I want to end up with a table Account with fields
Id
Name
SomeAdditionalInfo
This way i can keep reusing the BaseModel (and logic) in several similar projects.
I guess i can't use partial classes because we're speaking different DLL's.
Maybe inheritance? I tried several ways but i keep getting conflicts about having 2 models with the same name.
Any hints? tips? solutions?
You can use inheritance though Table per Hierarchy.
You can create base class AccountBase and child class Account:AccountBase:
public class AccountBase
{
public Id { get;set;}
public string Name {get;set;}
}
public class Account : AccountBase
{
public string SomeAdditionalInfo { get;set;}
}
It generates Table AccountBase that will contains columns Id, Name, SomeAdditionalInfo
There will be also column Discriminator that will contains instance of what class contains in this row.

Categories

Resources