SingleResult Web Api remove Queryable - c#

I've been trying to access my object <User> by using SingleResult.Create().
The issue here is that my API is returning a wrapped object containing [1] element.
{"Queryable":[{"FirstName":"John","LastName":"Doe","UserName":"JohnDoe","Id":1}]}
When using SingleResult<T>, I've seen that is possible to return 1 single element of a type like this:
{"FirstName":"John","LastName":"Doe","UserName":"JohnDoe","Id":1}
I would like to remove {"Queryable":[]} from my SingleResult<T>
Please Help :D

The problem is that your SingleResult.Create() is creating a wrapper object for your entity, where what you SEEM to want is the entity itself. Either use another method internal to your project that doesn't wrap your object (no idea what that would be), or change the signature of your method and return the entity directly.
[HttpGet]
public virtual TEntity GetById(int id)
{
try
{
var data = GetDataById(id);
return data;
}
catch (Exception e)
{
throw e;
}
}
public virtual TEntity GetbyId(int id)
{
var data = _ctx.Set<TEntity>().Where(e => e.Id == id);
var entity = data.FirstOrDefault();
return entity;
}

Related

Get a value of an anonymous object in an anonymous method

I'm trying to write a general method like:
protected async Task<ResultModel<TU>> GetEntityByIdAsync<TU, TKey>(TKey id) where TU : class
{
try
{
var result = await _db.Set<TU>().FirstOrDefaultAsync(x =>
x.GetType().GetProperty("Id").GetValue(???).ToString() == id.ToString());
return result.ToResultModel();
}
catch (Exception ex)
{
_logger.Error($"Error In GetEntityByIdAsync {typeof(TU).Name}. Error: {ex}");
throw;
}
}
but I cannot figure it out what should I put in GetValue(???).
any help?
While you can get it working as you are trying to do, what you will find is that Entity Framework Core is not able to parse the reflection code, meaning it will run the FirstOrDefaultAsync in memory. So if you have a table with 1000 rows, all of those rows will be extracted from the database and filtered there. There's a few solutions:
Use the DbSet.Find method, this looks like it will do exactly what you are trying to achieve. For example:
var entity = await _db.Set<TU>().FindAsync(id)
Make your entities implement a common interface, for example:
public interface IEntity
{
int Id { get; }
}
Meaning your entities will look something like this:
public class SomeEntity : IEntity
{
public int Id { get; set; }
}
And finally your method now looks a lot simpler:
protected async Task<ResultModel<TU>> GetEntityByIdAsync<TU, TKey>(TKey id)
where TU : IEntity
{
return await _db.Set<TU>.FirstOrDefaultAsync(x => x.Id == id);
}
Build up an expression manually. This is a lot more involved and I'm not going to show how to do it as it's almost certainly not needed in this situation.

Entity Framework and MVC: generating CONTROLLER code from entities

I'm on an assignment to to expose SQL data using MVC via OData.
I'm working with an existing project, Visual Studio 2015.
A bunch of tables have already been exposed.
Please first accept my apologies for perhaps a poorly crafted post.
I'm having a hard time figuring out what I'm actually working with.
In addition, I've had only a day to familiarize myself with this project.
I know that I said MVC but as far as I can tell, this project does not have VIEWS. I do believe however that the consumers of this project will read JSON.
I've used the Entity Framework to build the MODEL for the additional tables required to finish my assignment.
I'm working now on the CONTROLLER code, and I'd like to use a tool to automate that portion as much as possible. Below please find an example of a CONTROLLER already defined. I include that to help you get a feel for the type of tool I'm looking for.
Does such a tool exist? Or do I have to notepad a CONTROLLER for the tables that I've added to the project?
Thank you kindly for reading my post and for any assistance you can offer :)
public class BlockController : ODataController
{
AccordNewModel _db = new AccordNewModel();
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Get()
{
return Ok(_db.Block.AsQueryable());
}
[ODataRoute()]
[HttpPost]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Post(Block newBlock)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_db.Block.Add(newBlock);
_db.SaveChanges();
return Created(newBlock);
}
[ODataRoute()]
[HttpPut]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Put(Block block)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_db.Block.AddOrUpdate(p => new { p.BlockID }, block);
_db.SaveChanges();
return Updated(block);
}
[HttpDelete]
public IHttpActionResult Delete([FromODataUri] int key)
{
var block = _db.Block.SingleOrDefault(t => t.BlockID == key);
_db.Block.Remove(block);
_db.SaveChanges();
return Content(HttpStatusCode.NoContent, "Deleted");
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
It makes little sense to write very similar controller code multiple times, I would advise against generating 1 controller per entity. Instead you could use a generic solution:
public class BaseController<T> : ODataController
{
AccordNewModel _db = new AccordNewModel();
[EnableQuery]
public IHttpActionResult Get()
{
return Ok(_db.Set<T>().AsQueryable());
}
[HttpPost]
public IHttpActionResult Post(T posted)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var added = _db.Set<T>().Add(posted);
_db.SaveChanges();
return Created(added);
}
//Etc... Write generic controller methods using Db.Set<T>()
Then for every entity you need not do much, here is how your 'block' entity controller would look:
public class BlockController : BaseController<Block> { }
For delete and update you need some way to identify the generic object of T by Id (int key). I know of two ways to do this:
1: Let your entities implement an interface IHasId which ensures they have an int Id property, then add a generic constraint to the BaseController class like so: public class BaseController<T> : ODataController where T : IHasId. Delete method could look like this:
[HttpDelete]
public IHttpActionResult Delete([FromODataUri] int key)
{
var found = _db.Set<T>().FirstOrDefault(e => e.Id == key);
if(found != null)
{
_db.Set<T>().Remove(found);
_db.SaveChanges();
return StatusCode(System.Net.HttpStatusCode.NoContent);
}
else
{
return NotFound();
}
}
Or, 2: Make the BaseController class abstract and add: protected abstract T GetById(int id);. Then inheriting classes (such as 'BlockController') must implement a method to get the object from the Db by id. You will have to implement this method for every entity, this is still less work than writing individual controllers for every entity. The delete method would look almost the same as the one above except: var found = GetById(key);.
I use Delete as an example, but if you have some way to get an entity by id you can quite easily implement the Post and possibly a Get(int key) as well.
With this generic base class the code per entity is minimal and writing it for every entity shouldn't be too much work.

WebApi 2.0 OData, obtain list of SQL tables used in the query

I have a fairly standard WebApi 2.0 OData 4.0 webservice using EF5, and code first approach. This service works and I can query entities and related entities through foreign keys.
The service is read-only and the controllers only have a Get and Get-by-key implemented.
public class MyTableController : MyDbController
{
[EnableQuery]
public IQueryable<MyTable> Get()
{
return db.MyTable;
}
[EnableQuery]
public SingleResult<MyTable> Get([FromODataUri] int key)
{
IQueryable<MyTable> result = db.MyTable.Where(p => p.pk == key);
return SingleResult.Create(result);
}
}
In both Get() implementations, I would like to have access to the list of tables that are being used in the OData and resulting SQL query. MyTable is obviously one of them, but how do I obtain the others (among others, the ones used in (nested) $expand)? I can try to parse the URL myself, but that's doesn't seem like a very good way to go about it.
Create a class CustomizeAttribute inherit from EnableQueryAttribute
Override this method : public virtual IQueryable ApplyQuery
then you get the queryOptions in this method, you can go to the SelectExpandQueryOption and find the ExpandItem, then you get all the table.
public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
{
if (queryOptions.SelectExpand != null)
{
foreach (var selectItem in queryOptions.SelectExpand.SelectExpandClause.SelectedItems)
{
var expandedItem = selectItem as ExpandedNavigationSelectItem;
if (expandedItem != null)
{
// get the entitySetName, tableName
string entitySetName = expandedItem.NavigationSource.Name;
// can go recursive with expandItem.SelectExpandClause in case we have $epxand=A($expand=B)
}
}
}
return base.ApplyQuery(queryable, queryOptions);
}
Use this attribute on Controller method
[CustomizeAttribute]
public IQueryable<MyTable> Get()
{
return db.MyTable;
}

Custom value type, EF Code First and routing

In our WebApi project we use EF CodeFirst approach. Also we use 2 types of databases: SQL Server and MySQL. All tables have the field ID, but in SQL Server database this field has int data type, in MySQL database this field is char(36) and contains GUID.
To solve the problem I created a custom value type like IdType and changed all model classes to use that type insted int:
public class Document
{
public IdType ID { get; set; }
public string DocumentNm { get; set; }
...
}
Then I configured the DbContext (e.g for SQL Server)
modelBuilder.Properties<IdType>().Configure(c => c.HasColumnType("int"));
...and changed repository:
public interface IRepository<T> where T : IEntity
{
IQueryable<T> GetAll();
T GetById(IdType id);
...
}
After that, when I try to go to e.g. http://localhost:7081/api/Document, it gives me an error:
Multiple actions were found that match the request: \r\nGet on type
WebUI.Controllers.API.DocumentController\r\nGetById on type
WebUI.Controllers.API.DocumentController
I use default settings of routing. Here is [HttpGet] methods from DocumentController:
public HttpResponseMessage Get() { ... }
public HttpResponseMessage GetById(IdType id) { ... }
How can I solve the problem? Could this be the cause of incorrect implementation of IdType?
P.S. I created IdType for int values as described here. if I have to add more informations, please let me know.
UPDATE
DocumentController:
public HttpResponseMessage GetById(IdType id)
{
var entity = repository.GetById(id);
if (entity == null)
{
return ErrorMsg(HttpStatusCode.NotFound, string.Format("No {0} with ID = {1}", GenericTypeName, id););
}
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
My repository:
public virtual T GetById(IdType id)
{
return GetAll().FirstOrDefault(x => x.ID == id);
}
public virtual IQueryable<T> GetAll()
{
return entities = context.Set<T>();
}
It seems that it not implemented yet in current version of Entity Framework
And as mentioned in task on GitHub
we're currently planning to work on lighting this feature up after our
initial RTM of EF7.

SingleOrDefault in generic repository?

I implement repository pattern in my current web api project with EF6. Currently, I have the following function (in CustomerRepository) that returns a customer:
public override Customer Get(int id, params Expression<Func<Customer , object>>[] include)
{
if (include.Any())
{
var set = include.Aggregate<Expression<Func<Customer , object>>, IQueryable<Customer >>
(dbset, (current, expression) => current.Include(expression));
return dbset.SingleOrDefault(x => x.Id == id)
}
return dbset.Find(id);
}
This works fine, but I would like to move the above method in my generic repository. The problem here is SingleOrDefault, because Id wouldn't be known for T.
Is there a way to solve this? Do I need to implement an interface?
As a side not, the first property of ALL of my entities is 'int Id'.
This works fine,
Hmmm, are you sure about that:
return dbset.SingleOrDefault(x => x.Id = id)
shouldn't this be:
return dbset.SingleOrDefault(x => x.Id == id)
Anyway, if all your entities have an integer Id property, why not have them all implement an interface:
public interface IEntity
{
int Id { get; }
}
and then you will constrain your generic T parameter to this interface in the base repo and you will know how to write the lambda.
EF6 has a Find() method that sort of does what you need.
http://msdn.microsoft.com/en-us/library/gg696418(v=vs.113).aspx
public T Get(int id)
{
return dbset.Find(id);
}
Don't worry about it loading more joined tables (includes) than needed. It's not that big of a deal for a single record. EDIT: sorry, Find does not actually do any eager loading of its own. Related entities are only returned if they were already tracked by the context.

Categories