$orderBy with duplicate property in odata v4 - c#

I have the following models:
public class Field
{
public string Name { get; set; }
public int Order { get; set; }
public int FieldGroupId { get; set; }
}
public class FieldGroup
{
public string Name { get; set; }
public int Order { get; set; }
public virtual ICollection<Field> Field { get; set; }
}
And what I am want to do is a query where I can order first by the group and then by the field, like:
http://localhost:44300/API/odata/IntFieldSet?$count=true&$expand=FieldGroup&$orderby=FieldGroup/Order,Order
However, when I try it I receive the following error:
Duplicate property named 'Order' is not supported in '$orderby'.
Although they have the same name, they are not the same field. If I try order by fields with different names or only one of those per time, it works. Ex:
$orderby=FieldGroup/Order,Name || $orderby=FieldGroup/Order || $orderby=Order
It used to work on odata v3 but not anymore that I am using odata v4.
Anyone have faced this problem before. Can you help me to find out a solution?
Thanks in advance.

I have the same issue using WebAPI OData 5.6 and 5.7.
However they say they fixed it in version WebAPI Odata 5.7: https://github.com/OData/WebApi/issues/376
Will wait for publication of the update.

It is fixed now.
The correct query should look something like:
http://localhost:44300/API/odata/IntFieldSet?$count=true&$expand=FieldGroup&$orderby=FieldGroup/Order asc,Order desc
It will rougly be translate to:
.OrderBy(x => x.FieldGroup.Order).ThenByDescending(x => x.Order);
Here's an example from odata.org:
http://services.odata.org/TripPinRESTierService/Airports?$orderby=Name%20asc,%20Location/Address%20desc

Related

Conditional Include in asp.net core and Entity Framework

I just started my first project using asp.net core and for the first time I'm gonna use the code repository for my project in C# and VS 2019.
I create a new Model and it called Comment. This Table can save all of the comments on the project, That mean is user comments in POSTS, SOCIALMEDIA, and etc Areas saved in this table
[Key]
public int CommentId { get; set; }
public eTable Table { get; set; }
public int ContentId { get; set; }
[StringLength(1500)]
public string Notes { get; set; }
public virtual AnalysedMarket AnalysedMarket { get; set; }
ContentID is my foreign key, And my eTable enum type is like bellow:
public enum eTable
{
AnalysedMarket,
Blog,
News,
Migration,
}
I created a new class for AnalysedMarket as well to save Users data from our social media area.
[Key]
public int AnalysedMarketId { get; set; }
[StringLength(255)]
public string Images { get; set; }
public int Hits { get; set; }
public string Notes { get; set; }``
Now I created a method in my code repository for extract data using EF and LINQ to get list of AnalysedMarket data but I can't Include my result with Comment table and result of my code repository in the comment section is null always.
public async Task<IEnumerable<AnalysedMarket>> List(int? page, int? perPage, eStatus? status, string userId)
{
var query = _db.AnalysedMarkets.Select(a => a);
if (status.HasValue)
query = query.Where(m => m.Status.Equals(status));
if (!string.IsNullOrEmpty(userId))
query.Where(m => m.CreatedBy.Equals(userId));
query.Include(a => a.Comments.Where(c => c.Table.Equals(eTable.AnalysedMarket) && c.ContentId == a.AnalysedMarketId));
if (page.HasValue && perPage.HasValue)
return await query.OrderBy(a => a.AnalysedMarketId).ToPagedListAsync(page.Value, perPage.Value);
else
return await query.OrderBy(a => a.AnalysedMarketId).ToListAsync();
}
Actually my question is how can I get list of AnalysedMarket data included by Comment data.
And it has a condition and it says include comment if ContentId is equal to AnalysedMarketId and eTable is Table.AnalysedMarket.
I read the articles about conditional Include but I didn't get any thing of them.
Example 1
Example 2
You need to add a reference from AnalysedMarket to comment like this in your AnalysedMarket-Class:
ICollection<Comment> Comments { get; set; }
And then include them while querying your AnalysedMarkets like this:
var query = _db.AnalysedMarkets.Include(c => c.Comments);
/Edit:
Regarding your comment - for this you would need kind of an hierarchy/inheritance structure. It seems to be supported by EfCore and something like this should work:
public class CommentableItem {
ICollection<Comment> Comments {get;set;}
}
public class Comment {
CommentableItem CommentableItem {get;set;}
}
public class AnalysedMarket : CommentableItem {
}
Than you should be able to use the include for each item inheriting from CommentableItem. I did not use the inheritance feature yet (as far as I know this is quite new for EF Core), so for further instructions check the documentation

How to update or insert an item in RethinkDB?

I am trying to update or insert (if it does not exist) an element in the database but so far I have not found any examples on how to use the Update and Filter provided by the C# Api.(C# Api , not RethinkDB Reql).
Link to api : https://github.com/bchavez/RethinkDb.Driver
Can anyone help me ?
POCO
class Player
{
public long playerId { get; set; }
public long groupId { get; set; }
public int type { get; set; }
public double lat { get; set; }
public double lng { get; set; }
}
class PlayerRequest
{
public Player data { get; set; }
public Auxdata aux { get; set; }
}
This would be the insert request:
dynamic rez = await r.Db(Constants.DB_NAME).Table(Constants.TABLE_CLIENT)
.Insert(playerRequest.data).RunAsync(Con);
I need to perform an update of playerRequest.data based on the playerId or insert the Player if it does not exist.
I have searched the Api but so far no success.
P.S I have tried installing the Linq to ReQL extension, but the methods seam to be unavailable.
After searching and asking the author of the driver which helped me greatly (thank you Brian!) the solution is the following:
In Js we define adhoc objects with {prop1:value1,prop2,value2}
The C# equivalent is using anonymous types: new{prop1:value1,prop2:value2}
r.Db(Constants.DB_NAME).Table(Constants.CLIENT_TABLE)
.Filter(new { playerId = playerRequest.data.playerId })
.Update(new { lng = playerRequest.data.lng, lat = playerRequest.data.lat })
.RunResult<QueryResult>(this.Con);
Also for further explanation you must read this section of the github repository wiki:
https://github.com/bchavez/RethinkDb.Driver/wiki/Extra-C%23-Driver-Features
When in doubt on how to use a method check the Java driver implementation,they are similar (The C# driver extends the Java one)

EF6 Linq Query .Include only returning first entry of child table

I would like to retrieve a list of Encounters for a Given Pokemon, as a Pokemon can be encountered in many places, so I've been trying many variants of
var currentPokemon = _context.Pokemon
.Where(mon => mon.Id == id)
.Include(mon => mon.Encounters)
.FirstOrDefault();
With the result being a Pokemon object with all of the relevant data, but only the FIRST encounter being retrieved and put into a collection resulting in this:
Looking at the database, there are about 20 encounters for caterpie, and I'd like access to all of them, but only ever just get the one.
What the Pokemon class looks like (irrelevant fields omitted):
[Table("pokemon")]
public partial class Pokemon {
public Pokemon()
{
Encounters = new HashSet<Encounters>();
}
[Column("id")]
public long Id { get; set; }
[Required]
[Column("identifier", TypeName = "VARCHAR(79)")]
public string Identifier { get; set; }
.
.
.
[InverseProperty("Pokemon")]
public virtual ICollection<Encounters> Encounters { get; set; }
}
What Encounters looks like:
public partial class Encounters {
.
.
.
[ForeignKey("PokemonId")]
[InverseProperty("Encounters")]
public virtual Pokemon Pokemon { get; set; }
}
Db data :
What am I misunderstanding here?
I think its because you are calling .FirstOrDefault(), which is only getting the first item. Can you omit that and add .ToList()? Also, var currentPokemon doesn't seem like a good variable name. You said you want a list of Encounters, right? How about var pokemonEncounters?
I think that the problem is the way that you set the relationship using ForeignKey and InverseProperty.
Try to rewrite to something like:
[Table("Pokemon")]
public class Pokemon
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("Pokemon")]
public ICollection<Encounter> Encounters { get; set; }
}
[Table("Enconters")]
public class Encounter
{
public int Id { get; set; }
public int PokemonId { get; set; }
[ForeignKey("PokemonId")]
public Pokemon Pokemon { get; set; }
}
My apologies, I've been looking to the wrong places for my answer. After stepping through this in a debugger, I can see that my Pokemon query does indeed return the desired result: A pokemon with many encounters attached. My problem seems to be elsewhere (specifically: the JSONified object I'm seeing come through to my web front-end truncates the encounters array to contain only the first result).
I'll post a new question with the correct problem and link to it from here when it's figured out.

Entity Framework (5.0) Code First - Insert into Collection within Collection

I've got three classes.
Event > Workshop > Workshop Times
I'm currently looking for best way of inserting records into the Workshop Times, this is running through code first using ICollections.
Looking for something along the lines of this, but I know it doesn't work:
//Create connection
var db = new Context();
var Event = db.Events
.Include("Workshops")
.Include("Workshops.Times")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Event.Workshops.Add(new Workshop
{
Name = tbWorkshopName.Text,
Description = tbWorkshopDescription.Text,
Times.Add(new WorkshopTime{
//Information for times
})
});
db.SaveChanges();
Chopped down classes:
public class Workshops{
public int id { get; set; }
public string name { get; set; }
public ICollection<WorkshopTimes> Times{get;set;}
}
public class Events {
public int id { get; set; }
public string name { get; set; }
public ICollection<Workshops> WorkShops { get; set; }
}
public class WorkshopTimes {
public int id { get; set; }
public DateTime time { get; set; }
}
You are definitely on the right track with your query, however your include statements appear incorrect. From your model I would expect:
var Event = db.Events
.Include("WorkShops")
.Include("WorkShops.events")
.Where(ev => ev.GUID == EventGUID).FirstOrDefault();
Note this uses the property names not the types. This will ensure that the entities in the listed nav properties will be included in the result.
In addition you can use a lambda to do the same thing (but its typesafe)
Check out here for how to do a very similar scenario to yours:
EF Code First - Include(x => x.Properties.Entity) a 1 : Many association
or from rowan miller (from EF team)
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
And make sure you are using System.Data.Entities for lambda based includes ( Where did the overload of DbQuery.Include() go that takes a lambda? )

Exclude a field/property from the database with Entity Framework 4 & Code-First

I will like to know that is there a way to exclude some fields from the database? For eg:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string FatherName { get; set; }
public bool IsMale { get; set; }
public bool IsMarried { get; set; }
public string AddressAs { get; set; }
}
How can I exclude the AddressAs field from the database?
for future reference: you can use data annotations
MSDN EF - Code First Data Annotations
[NotMapped]
public string AddressAs { get; set; }
I know this is an old question but in case anyone (like me) comes to it from search...
Now it is possible in entity framework 4.3 to do this. You would do it like so:
builder.Entity<Employee>().Ignore(e => e.AddressAs);
In the current version the only way to exclude a property is to explicitly map all the other columns:
builder.Entity<Employee>().MapSingleType(e => new {
e.Id,
e.Name,
e.FatherName,
e.IsMale,
e.IsMarried
});
Because AddressAs is not referenced it isn't part of the Entity / Database.
The EF team is considering adding something like this:
builder.Entity<Employee>().Exclude(e => e.AddressAs);
I suggest you tell leave a comment on the EFDesign blog, requesting this feature :)
Hope this helps
Alex
It's also possible to add the column you want to ignore as a Shadow Property in the DbContext:
builder.Entity<Employee>().Property<string>("AddressAs");
Then you can query on that column like so:
context.Employees.Where(e => EF.Property<string>(e, "AddressAs") == someValue);

Categories