Problem with: Dapper Extensions dbConnection.Get(personId)
I have a model called Person:
Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
In the database I have this table:
data.Persons
Pers_Id
Pers_Name
When I try this without any kind of custom mapping, I get an error "Invalid object name 'Person'."
I believe this is a mapping issue, because when I completely map the model with the prefix 'Pers_', and use 'data.Persons'
Get works.
But is there a way to automatically map with a prefix? The database I'm using has many different tables
with different prefices.
I also have everything already mapped to Entity framework. Is there a possibility of getting the map settings from
Entity DbModelBuilder?
Dapper-Extensions is convention based. For schema, it uses .dbo and for primary key it uses Id. If your tables don't match the convention, you will have to create a custom mapping.
public class MyModelMapper : ClassMapper<MyModel>
{
public MyModelMapper()
{
//use different table name
Table("table_name");
//use a custom schema
Schema("not_dbo_schema");
//have a custom primary key
Map(x => x.ThePrimaryKey).Key(KeyType.Assigned);
//Use a different name property from database column
Map(x=> x.Foo).Column("Bar");
//Ignore this property entirely
Map(x=> x.SecretDataMan).Ignore();
//optional, map all other columns
AutoMap();
}
}
An alternative is to use Dapper and just write your inline queries:
connection.Query("select * from foo.table where myId = {myId}", new {myId})
Update:
Another alternative is to play around with Code Generation and T4 Text Templates
Here is a trivial example
Related
I want to create a enum type column named 'type' but when I reverse engineer my Code First generated DB it assigns it as an 'int'.
Here is my Enum class:
[Flags]
public enum TypeNames
{
Een = 0,
Twee = 1,
Drie = 2
}
Here is my Grounds class to create the table with the 'TypeNames'-enum. The Properties class is another table (Grounds - Properties have a TPT inheritance).
[Table("gronden")]
public partial class Grounds : Properties
{
[Column("opp")]
public double? Surface { get; set; }
[EnumDataType(typeof(TypeNames)), Column("type")]
public TypeNames Types { get; set; }
}
Any ideas of what I am missing here to get an enum-type into my DB?
According to the following answer, it appears that EnumDataTypeAttribute is only implemented for ASP.NET UI components, and not for EF usage.
Should the EnumDataTypeAttribute work correctly in .NET 4.0 using Entity Framework?
EF Core 2.1 implements a new feature that allows Enums to be stored as strings in the database. This allows data to be self-describing, which can be really helpful for long-term maintainability. For your specific case, you could simply do:
[Table("gronden")]
public partial class Grounds : Properties
{
[Column("opp")]
public double? Surface { get; set; }
[Column("type", TypeName = "nvarchar(24)")]
public TypeNames Types { get; set; }
}
You can find more detail on this page:
https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions
Also, I noticed that you have the FlagsAttribute set on your enum. Are you hoping to be able to apply multiple enum values to a single entity? This should work fine when values are persisted as an int, but will not work if storing as a MySQL ENUM or string datatype. MySQL does support a SET datatype, but it seems unlikely that EF would add support for this feature, since most other databases don't have a similar concept.
https://dev.mysql.com/doc/refman/5.6/en/constraint-enum.html
If you do indeed want to allow multiple enum values to be applied to each entity (similar to the way tags are used on Stack Overflow), you might consider creating a many-to-many relationship instead. Basically, this would mean converting the TypeNames enum into a Types table in the database, and allowing EF to generate a GroundTypes table to link them together. Here is a tutorial:
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
With its recent improvements, I'm looking to move from Dapper back to EF (Core).
The majority of our code currently uses the standard patterns of mapping entities to tables, however we'd also like to be able to make simple ad-hoc queries that map to a simple POCO.
For example, say I have a SQL statement which returns a result set of strings. I created a class as follows...
public class SimpleStringDTO
{
public string Result { get; set; }
}
.. and called it as such.
public DbSet<SimpleStringDTO> SingleStringResults { get; set; }
public IQueryable<SimpleStringDTO> Names()
{
var sql = $"select name [result] from names";
var result = this.SingleStringResults.FromSql(sql);
return result;
}
My thoughts are that I could use the same DBSet and POCO for other simple queries to other tables.
When I execute it, EF throws an error "The entity type 'SimpleStringDTO' requires a primary key to be defined.".
Do I really need to define another field as a PK? There'll be cases where there isn't a PK defined. I just want something simple and flexible. Ideally, I'd rather not define a DBSet or POCO at all, just return the results straight to an IEnumerable<string>.
Can someone please point me towards best practises here?
While I wait for EF Core 2.1 I've ended up adding a fake key to my model
[Key]
public Guid Id { get; set; }
and then returning a fake Guid from SQL.
var sql = $"select newid(), name [result] from names";
Is it possible to call a TVF in EF6 Code First?
I started a new project using EF6 Database first and EF was able to import a TVF into the model and call it just fine.
But updating the model became very time consuming and problematic with the large read-only db with no RI that I'm stuck dealing with.
So I tried to convert to EF6 code first using the Power Tools Reverse Engineering tool to generate a context and model classes.
Unfortunately the Reverse Engineering tool didn't import the TVFs.
Next I tried to copy the DBFunctions from my old Database First DbContext to the new Code First DbContext, but that gave me an error that my TVF:
"cannot be resolved into a valid type or function".
Is it possible to create a code first Fluent mapping for TVFs?
If not, is there a work-around?
I guess I could use SPs instead of TVFs, but was hoping I could use mostly TVFs to deal with the problematic DB I'm stuck with.
Thanks for any work-around ideas
This is now possible. I created a custom model convention which allows using store functions in CodeFirst in EF6.1. The convention is available on NuGet http://www.nuget.org/packages/EntityFramework.CodeFirstStoreFunctions. Here is the link to the blogpost containing all the details: http://blog.3d-logic.com/2014/04/09/support-for-store-functions-tvfs-and-stored-procs-in-entity-framework-6-1/
[Tested]
using:
Install-Package EntityFramework.CodeFirstStoreFunctions
Declare a class for output result:
public class MyCustomObject
{
[Key]
public int Id { get; set; }
public int Rank { get; set; }
}
Create a method in your DbContext class
[DbFunction("MyContextType", "SearchSomething")]
public virtual IQueryable<MyCustomObject> SearchSomething(string keywords)
{
var keywordsParam = new ObjectParameter("keywords", typeof(string))
{
Value = keywords
};
return (this as IObjectContextAdapter).ObjectContext
.CreateQuery<MyCustomObject>(
"MyContextType.SearchSomething(#keywords)", keywordsParam);
}
Add
public DbSet<MyCustomObject> SearchResults { get; set; }
to your DbContext class
Add in the overriden OnModelCreating method:
modelBuilder.Conventions.Add(new FunctionsConvention<MyContextType>("dbo"));
And now you can call/join with
a table values function like this:
CREATE FUNCTION SearchSomething
(
#keywords nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(SELECT KEY_TBL.RANK AS Rank, Id
FROM MyTable
LEFT JOIN freetexttable(MyTable , ([MyColumn1],[MyColumn2]), #keywords) AS KEY_TBL
ON MyTable.Id = KEY_TBL.[KEY]
WHERE KEY_TBL.RANK > 0
)
GO
I was able to access TVF with the code below. This works in EF6. The model property names have to match the database column names.
List<MyModel> data =
db.Database.SqlQuery<MyModel>(
"select * from dbo.my_function(#p1, #p2, #p3)",
new SqlParameter("#p1", new System.DateTime(2015,1,1)),
new SqlParameter("#p2", new System.DateTime(2015, 8, 1)),
new SqlParameter("#p3", 12))
.ToList();
I actually started looking into it in EF6.1 and have something that is working on nightly builds. Check this and this out.
I have developed a library for this functionality. You can review my article on
UserTableFunctionCodeFirst.
You can use your function without writing SQL query.
Update
First of all you have to add reference to the above mentioned library and then you have to create parameter class for your function. This class can contain any number and type of parameter
public class TestFunctionParams
{
[CodeFunctionAttributes.FunctionOrder(1)]
[CodeFunctionAttributes.Name("id")]
[CodeFunctionAttributes.ParameterType(System.Data.SqlDbType.Int)]
public int Id { get; set; }
}
Now you have to add following property in your DbContext to call function and map to the property.
[CodeFunctionAttributes.Schema("dbo")] // This is optional as it is set as dbo as default if not provided.
[CodeFunctionAttributes.Name("ufn_MyFunction")] // Name of function in database.
[CodeFunctionAttributes.ReturnTypes(typeof(Customer))]
public TableValueFunction<TestFunctionParams> CustomerFunction { get; set; }
Then you can call your function as below.
using (var db = new DataContext())
{
var funcParams = new TestFunctionParams() { Id = 1 };
var entity = db.CustomerFunction.ExecuteFunction(funcParams).ToList<Customer>();
}
This will call your user defined function and map to the entity.
I'm currently using EF5 in a project with a legacy database. The legacy application uses dynamically build tables (xxxx_year, yyyy_year) to store "year based data". I've been trying to find a way to dynamically map the ef entities (xxxx, yyyy, etc) to the tables, based on the year property value, but I always end up getting the "The model backing the context has changed since the database was created." error. Can anyone give me some ideas on how to accomplish this ?
I found some old blog posts talking about edm mapping, where we can separate mapping tables based on some property value (kind of horizontal partitioning), but I can't find any pointers on how to accomplish the same using code first.
Thanks, P
In your mapping configuration for each domain object, you can tell EF that the corresponding table name for an entity is different from the entity name itself.
If your class is called YyyyYear, it can point to a table called "2012_year" by specifying the name in its mapping file.
e.g.
// 1 entity class per db table
public class YyyyYear
{
public int Id { get; set; }
}
// 1 mapping file for entity
using System.Data.Entity.ModelConfiguration;
public class YyyyYearMap: EntityTypeConfiguration
{
public YyyyYearMap()
{
this.HasKey(t => t.Id);
this.ToTable("2012_year");
}
}
// your db context class (derives from DbContext)
using System.Data.Entity;
public class MyDbContext: DbContext
{
// 1 db set for every entity/table
public DbSet YyyyYears { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// 1 mapping file for every entity/table
modelBuilder.Configurations.Add(new YyyyYearMap());
}
}
I'm not sure if that's what you're looking for, but I have a blog post with step-by-step instructions, a working sample, and how to resolve common issues.
http://wakeupandcode.com/entity-framework-code-first-migrations/
Hope this helps!
When creating POCO classes that contain collections of primitive types and are persisted by EF Code First, the best advice I have found so far is to create a new class that has an ID plus the primitive type:
Entity Framework and Models with Simple Arrays
If I now have several classes that require properties of type ObservableCollection<string> and replace them with ObservableCollection<EntityString> (where EntityString is a custom type with an Id and a string property), I end up with a table EntityString that has multiple foreign key columns, one for each property of type ObservableCollection<EntityString> across all concrete types with such properties.
This leads to a bloating of mostly-null foreign key columns in the EntityString table.
One approach would be to create a subclass of EntityString and use the Table per Type model for those subclasses. However, that requires making awkward changes to the object model simply to accommodate Entity Framework.
Questions:
Is the encapsulating type the best way to manage Collection<PrimitiveType>?
If so, what are the pro's and con's of allowing multiple (many) foreign key columns vs. creating custom tables per type (at the cost of an awkward model)?
Promoting simple type to entity is one option. If you want to use that new primitive type entity in more relations it is better to completely remove navigation properties from that entity and use independent association (no FK properties).
public class StringEntity
{
public int Id { get; set; }
public string Text { get; set; }
}
and mapping:
modelBuilder.Entity<Foo1>().HasMany(f => f.Strings).WithOptional();
modelBuilder.Entity<Foo2>().HasMany(f => f.Strings).WithOptional();
In database you will get new nullable FK per related principal - there is no way to avoid it except create special StringEntity class per principal (don't use inheritance for that because it affects performance).
There is an alternative:
public class StringEntity
{
public int Id { get; set; }
public List<string> Strings { get; private set; }
public string Text
{
get
{
return String.Join(";", Strings);
}
set
{
Strings = value.Split(";").ToList();
}
}
}
In this case you don't need related entity type (and additional table) but your entity is polluted with additional property Text which is only for persistence.