I have a table foo where one of the column is bar of type jsonb which contains property foo_bar jsonb.
I want to get count of elements with such ef core query:
await dbContext.Foo.CountAsync(x => x.bar.FooBar.Name == "some name");
Ef core generates such query:
SELECT COUNT(*)::INT
FROM foo AS f
WHERE f.bar#>>'{FooBar,Name}' = 'SomeName'
It doesn't work for me because of instead of right property name foo_bar ef core generates FooBar (as my .net property) and instead of name ef core generates Name.
If there a way to make ef core generate the following query:
SELECT COUNT(*)::INT
FROM foo AS f
WHERE f.bar#>>'{foo_bar,name}' = 'Production'
I tried to mark my FooBar property with [JsonPropertyName("foo_bar")] attribute.
Also I tried to use fluent approach:
entity.Property<FooBar>("FooBar").HasColumnName("foo_bar").HasColumnType("jsonb");
Both of them doesn't work.
Support for [JsonPropertyName] has just been added, and will work starting from version 5.0.0-preview6.
I Found a workaround - name .net properties as they named in db.
So in my case it would be .net property like:
public FooBar foo_bar { get; set; }
Looks ugly, but works
Related
I'd like to create a generated tsvector column using npgsql / dotnet on a shadow property. I do not want to place the tsvector column in the entity class as I'd like to keep the domain entities agnostic of any specific database.
One way that may work is to use a shadow property for the tsvector column. I am able to create the tsvector column and index, but have not been able to figure out how to create generated column definition.
If the property exists in the domain entity, I can use the following:
builder
.HasGeneratedTsVectorColumn(
c => c.SearchVector,
"english",
c => new { c.Number, c.Name })
.HasIndex(p => p.SearchVector)
.HasMethod("GIN");
If the property is not in the domain, but rather a shadow property, I tried something like the foolowing:
builder
.Property<NpgsqlTsVector>("search_vector");
builder
.HasGeneratedTsVectorColumn(
c => EF.Property<NpgsqlTsVector>(c, "search_vector"),
"english",
c => new { c.ClientId, c.Name })
.HasIndex("search_vector")
.HasMethod("GIN");
Unfortunately, this does not work and, when generating the migrations, issues the following error:
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.ArgumentException: The expression 'c => Property(c, "search_vector")' is not a valid member access expression. The expression should represent a simple property or field access: 't => t.MyProperty'. (Parameter 'memberAccessExpression')
Is it possible to create the definition of the generated column for a shadow property?
Of course, also interested if there are other ways to accomplish this besides using a shadow property.
Thanks for any help,
Eric
I'm using EF 6.2.0, Code First from Database, in a .net 4.5.2 environment.
I have this DbSet:
<Table("Firebird.PLANT4")>
Partial Public Class PLANT4
<Key>
<DatabaseGenerated(DatabaseGeneratedOption.None)>
Public Property ID_PLANT4 As Integer
Public Property STATUS As Integer
<Required>
<StringLength(20)>
Public Property DESCRIPTION1 As String
Public Property COUNTER As Long
Public Property RESET_COUNTER As Integer
End Class
When I execute this code:
Using dbContext As New DbModel
dbContext.Database.Connection.ConnectionString = GetFbConnectionString()
dbContext.Database.Connection.Open()
Dim plant As PLANT4 = dbContext.PLANT4.Find(1)
plant.RESET_COUNTER = 1
dbContext.SaveChanges()
End Using
I get the error: "DESCRIPTION1 field is required".
The exception is throwing during SaveChanges.
I can't understand where the problem is, as if I watch "plant" in debug, all fields are there (ID_PLANT4 = 1 is an existing row), and DESCRIPTION1 in particular is not Nothing.
I can simply remove the "Required" attribute and it works, but the attribute is a consequence of the db column not allowing nulls, so I don't think this is the right way to go.
I can even add this line of code, just after the "Using" statement:
dbContext.Configuration.ValidateOnSaveEnabled = False
and it works, but again I don't think this is the right way to go.
What is the reason of this behavior?
Eventually I find that the problem is: field DESCRIPTION1 is populate by default with 20 spaces. It is not null, but it is a string formed only by spaces. For an unknown reason, during validation this string is treated by EF like null, and an exception is thrown because it's a required field.
"Required" attribute is not needed, but I generate my POCO classes by "Code First from Database", so if a VARCHAR field is declared as "not null" it is automatically generated with the "Required" attribute. Now I think it's better allowing nulls for VARCHAR columns.
Haven't seen this error before, and a cursory web search turns up very little. Here's (I think) the offending code:
this.HasMany(a => a.ListItems).WithRequired()
.Map(m =>
{
m.MapKey("AttributeId");
m.ToTable("ProductAttributeListItem");
}
)
;
And here's the full error:
The specified table 'ProductAttributeListItem' was not found in the
model. Ensure that the table name has been correctly specified.
The table is there and spelled correctly.
The lack of search results makes me think I'm missing something obvious. What might that be?
If you want to define the table name of the entity ListItems is refering to you need to do that on the entity, not in the relationship mapping:
modelBuilder.Entity<ListItem>() // or whatever the entity is called
.ToTable("ProductAttributeListItem");
And remove m.ToTable from the Map action.
I have a an entity referencing another entity by MappedLongForeignKey.
I am using the CRUDify trait and have a problem.
Entity 1:
id
title (String)
validTo (Date)
Entity 2:
id
...
fk_entity_1 (mapped via MappedLongForeignKey)
In the listings generated by CRUDify for entity 2 I would like to include a column formatted as
fk_entity_1.title ( fk_entity_1.validTo )
I tried to create a function returning such a string and adding that fn to fieldsForDisplay, but it seems fieldsForDisplay requires mapped fields.
Is this possible to accomplish?
* Edit *
What I am trying to accomplish is (using the built in functionality of CRUDify for listings) produce listings as:
{Entity 2 fields} "Entity 1"
... Title_X (2001-01-01)
... Title_Y (2011-02-02)
If worse comes to worst, I can roll my own listings, but I really like the CRUDify functionality.
I'm not quite sure what you're trying to accomplish, but maybe you could override the asHtml method of the fields instead?
I want to include child objects on an IQueryable list..
I want to include a child object on selected columns of some table type IQueryable list..
I tried like this:
IQueryable<Persons> persons = Context.Persons.Select(x=> new persons{Pkid=x.pkid, FirstName=x.FirstName}).AsQueryable();
persons= persons.Include("Address");
this include of child objects is not working..anyone please help...where I am doing wrong..
thanks alot...
Include doesn't work with projection. Moreover it is not needed. Just do this:
var query = context.Persons
.Select(x => new PersonDto
{
Id = x.pkid,
FirstName = x.FirstName,
Address = x.Address
});
Few points here:
No Include
Address accessed directly in projection, EF will handle this
I'm using PersonDto as target of projection. PersonDto has just Id, FirstName and Address.
You can project to custom type or anonymous type but you cannot project to entity type (the mapped type) - it doesn't work and it throws exception.
If you want to use mapped type you can't return only selected scalar columns - all columns will always be loaded. Only navigation properties can be loaded selectively. To overcome this people sometimes use Table splitting but that is something which works if you can divide your big entity into disjunct entities. In your scenario use just projection.
You cannot use Include() on a projection, try this:
Iquerable<Persons> persons = Context.Persons
.Include("Address")
.Select(x=> new persons{Pkid=x.pkid, FirstName=x.FirstName})
.AsQuerable();
Also you have a naming conflict, you project to a type persons and want to hold the results in an IQueryable named persons - one of them is wrong. Is there a reason you need the projection at all? You could just do
Iquerable<Persons> persons = Context.Persons.Include("Address");
First: Check if lazy loading is enabled or not. I experienced different results when it was enabled. I prefer lazy loading being disabled.
Second: Check this syntax:
result = (From person In context.Persons.Include("Address")).ToList();
P.S.: Useful EF Tips & Tricks : http://blogs.msdn.com/b/alexj/archive/2009/03/26/index-of-tips.aspx
UPDATE:
Include is not working, because your are using it on newly created objects, not the objects available in the context. you should use Include before creating new objects.
Check This:
result = (From person In context.Persons.Include("Address") Select New With {.FirstName = item.FirstName, .AddressValue = item.Address.Value}).ToList();