I have a problem with an OData controller that is a little unusual compared to the others I have. It is the first one working completely from memory - no database involved.
The returned entity is:
public class TrdRun {
[Key]
public Guid Identity { get; set; }
public TrdTrade [] Trades { get; set; }
TrdTrade is also an entity set (which if queries goes against a database). But in this particular case I want to return all trades associated as active from a run, and I an do so WITHOUT going to the database.
My problem? The following code:
[ODataRoute]
public IEnumerable<Reflexo.Api.TrdRun> Get(ODataQueryOptions options) {
var instances = Repository.TrdInstance.AsEnumerable();
var runs = new List<Reflexo.Api.TrdRun>();
foreach (var instance in instances) {
runs.Add(Get(instance.Identifier));
}
return runs;
}
correctly configures runs to have the trades initialized - but WebApi decides to swallow them.
What is a way to configure it to return the data "as given" without further filtering? I know about the AutoExpandAttribute (Which I would love to avoid - I do not want the API classes marked with OData attributes), but I have not enabled Query, so I would expect the return data to be returned as I set it up.
The value of the Trades property is not being serialized because the default behavior of ODataMediaTypeFormatter is to not follow navigation properties, regardless of what is in memory. You could override this behavior by using $expand in the query string of the request, or AutoExpandAttribute on the Trades property in the class definition, but both approaches require decorating your controller method with EnableQueryAttribute.
If you don't want to do any of that, you can still programmatically specify auto-expansion of Trades in your service configuration as follows:
// Let builder be an instance of ODataModelBuilder or a derived class.
builder.EntityType<TrdRun>().CollectionProperty(r => r.Trades).AutoExpand = true;
Minor issue: With the programmatic approach, if the client requests full metadata (e.g., odata.metadata=full in the Accept header), the OData serializer will not include full metadata in the auto-expanded objects.
Related
I've defined my own struct that represents DateTime with TimeZoneInfo so I can work with UTC time while keeping the information about timezone.
I would like to get these objects with OData query, but it fails when I try to use $orderby on this properties of this type. I was able to get results when I queried $orderBy=Timestamp/Value/UniversalTime but I would like to use just $orderBy=Timestamp
Is there any possibility to order collection with this type?
public struct DateTimeWithZone : IComparable<DateTime>, IComparable<DateTimeWithZone>, IFormattable
{
private readonly DateTime _utcDateTime;
private readonly TimeZoneInfo _timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
if (timeZone == null)
{
throw new NoNullAllowedException(nameof(timeZone));
}
_utcDateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
_timeZone = timeZone;
}
...
}
With model defined like this:
public class ClientViewModel
{
public string Name { get; set; }
public DateTimeWithZone? Timestamp { get; set; }
}
And this is how it is used:
public IHttpActionResult GetAll(ODataQueryOptions<ClientViewModel> options)
{
var fromService = _clientsClient.GetAllClients().MapTo<ClientViewModel>(MappingStrategy).AsQueryable();
var totalCount = fromService.Count();
var results = options.ApplyTo(fromService); // <-- Fails here
return Ok(new PageResult<ClientViewModel>(
results as IEnumerable<ClientViewModel>,
Request.ODataProperties().NextLink,
totalCount));
}
Fails with The $orderby expression must evaluate to a single value of primitive type.
we had some similar issue with complex type ordering. Maybe this can be of assistance in your scenario as well. In our case (which is not 100% identical) we use a two phase approach:
Rewriting ODataQueryOptions
separating the extneral model (ODATA) and the internal model (EntityFramework in our case)
Rewriting ODataQueryOptions
You mention that the format $orderBy=Timestamp/Value/UniversalTime is accepted and is processed properly by ODATA. So you can rewrite the value basically by extracting the $orderby value and reinserting it with in your working format.
I described two ways on how to do this in my post Modifying ODataQueryOptions on the fly (full code included), which take existing options recreate new options by constructing a new Uri. In your case you would extract Timestamp from $orderBy=Timestamp and reinsert as with $orderBy=Timestamp/Value/UniversalTime.
Separating External and Internal Model
In addition, we used two models for the public facing API and the internal / persistence layer. On the internal side we used different properties which we grouped into a navigation property (which only exists on the public side). With this approach the user is able to specify an option via an $expand=VirtualNavigationProperty/TimeZoneInfo and $orderby=.... Internally you do not have to use the complex data type, but keep using DateTimeOffset which already holds that information. I described this separation and mapping of virtual navigation properties in the following post:
Separating your ODATA Models from the Persistence Layer with AutoMapper
More Fun with your ODATA Models and AutoMapper
According to your question it should be sufficient to rewrite the query options in the controller as you did mention that the (little bit longer) $orderby format is already working as expected and you only wanted a more convenient query syntax.
Regards, Ronald
Can anyone post correct and useful an example of using EF lazy loading in MVC application?
I've tried to research the question, but I can't get proper case.
As a result my conclusion is: since web apps are stateless there is no sense to include LL to entities. But it sounds strange. That's why the question is here.
Can you confirm or otherwise refute my conclusion?
EDIT
The statment "stateless" in question context is important in my mind. Let's pretend 2 scenarios. First one relates for example to WPF app and the second one to MVC. Let's suppose that thre is the next simple object:
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
...
public virtual List<Activity> Activities { get; set; }
}
1) WPF. User is able to request the only Person without his Activities. Thus he get a small portion of data. Overhead are reasonable. At the same time user can decide to request person's activities.
Due to ll mechanism, EF simply loads activities without requesting person object again, since Person still exists in application (of course, if we code it in such a way).
2) MVC. The same actions are there. But the only difference that, after server response, all resources including object Person are disposes. And we can't load Person activities as we did in WPF application. We are forced to load Person again (overhead is increases comparing with WPF app)
The point is that Lazy loading can be executed only in the scope of the context to which the entity is attached - if you dispose the context you cannot use it.
I don't think you understand what lazy loading does, as it has nothing to do with whether there's any state or not. It's not like caching or something. Lazy loading is simply Entity Framework overloading a property to add a custom getter that issues a query to fetch the object or set of objects when the property is accessed for the first time.
For example, if you had something like:
public class Foo
{
public virtual Bar Bar { get; set; }
}
And you were to query a set of Foos from the database, the Bar property on all of them would be null, as EF would not have issued any queries yet to fetch the related Bar instance. However, if you were to iterate over this list of Foo and access some property on Bar (i.e. foo.Bar.Baz, then EF would issue a just-in-time query for the Bar instance, so that it could then return the Baz property on it.
I am attempting to create Web API controller in F# which returns objects from Entity Framework. SharpObject and SharpContext are my object and DbContext respectively defined in a c# project.
/// Retrieves values.
[<RoutePrefix("api2/values")>]
type ValuesController() =
inherit ApiController()
let values = [| "value1"; "value2" |]
/// Gets all values.
[<Route("")>]
member x.Get() : IEnumerable<SharpObject> =
use context = new SharpContext()
context.SharpObjects.ToList() :> IEnumerable<SharpObject>
Here is SharpObject with the SerializableAttribute.
[Serializable]
public class SharpObject
{
[Key]
public virtual int Id { get; set; }
public virtual string Description { get; set; }
}
The error that I am getting is this:
The type System.Data.Entity.DynamicProxies.SharpObject_3A697B5C46C0BF76858FEAFC93BFED36DD8D4CA2CEACBB178D2D3C38BB2D2052 was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
When I de-compile this using ILSpy, it looks like this:
[Route("")]
public IEnumerable<SharpObject> Get()
{
SharpContext context = new SharpContext();
IEnumerable<SharpObject> result;
try
{
result = (IEnumerable<SharpObject>)context.SharpObjects.ToList<SharpObject>();
}
finally
{
IDisposable disposable = context as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
return result;
}
What is the best way to get my list to show through in f#?
This happens because the object that you get from EF is not, in fact, of type SharpObject, but rather of that scarily named type, which inherits from SharpObject. This type is called "proxy" and is dynamically generated by EF in order to provide certain services (such as lazy loading, see below).
Because your action is declared as returning IEnumerable<SharpObject>, the default WebAPI's XML serializer expects to find object of that type, and so rightly complains upon finding an object of different type.
One temporary, bandaid-style fix that you can try is to remove the virtual keywords from your entity (why do you have them there, anyway?). It is the presence of the virtual keywords that causes EF to generate the proxy type. Absent virtual, no proxy will be generated, thus making the XML serializer happy.
This, however, will not work once you extend your model to include navigation properties with lazy loading. Those properties, you must make virtual, otherwise lazy loading won't work.
So the correct fix is not to use the same type for both DB-facing DTO and client-facing DTO. Use different types.
Using the same type for these two purposes may seem "convenient" at first, but this road quickly leads to numerous problems. One of small technical problems you have already discovered. But even absent those, conceptually, you almost never, ever want to just serve up your DB records directly to the untrusted user. Some of possible consequences include security holes, badly factored UI code, badly factored database structure, performance problems, and so on.
Bad idea. Don't do it.
P.S. This doesn't actually have anything to do with F#.
In my ASP.NET MVC project, my actions typically call a Service layer to get data. I use the same dozen or so POCOs for all my models. I also plan on using the Service layer in console applications and maybe expose a web api at some point.
To make my database operations more efficient, my service layer only hydrates the properties in the model that are relevant to the particular method (which at this point is mostly driven by the needs of my controller actions).
So for example I might have a class Order with properties Id, Name, Description, Amount, Items. For a given service call I might only need to populate Id, Name, Items. A consumer of that service won't necessarily know that Amount is 0 only because it didn't populate the property.
Similarly, the consumer won't know whether Items is empty b/c there actually aren't any items, or whether this particular service method just doesn't populate that property.
And for a third example, say one of my views displays an ItemCount. I don't want to fully populate my Items collection, I just need an additional property on my "model". I don't want to add this property to my POCO that other service methods will be using because it's not going to be populated anywhere else.
So the natural solution is to make a POCO designed specifically for that method with only those 3 properties. That way the consumer can know that all properties will be populated with its real values. The downside to this is that I'll end writing tons of similarly shaped models.
Any advice on which method works best?
You could use Nullable Types to indicate the missing properties with a null.
For example:
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
And then if Items == null, it wasn't set. If it's an empty new List<Item>(), it's set but empty. Same for Amount. If Amount.HasValue == false, it wasn't set. If Amount.Value is 0.0d, it's set and the item is free.
Why don't you use LINQ projection?
One service method does something like:
return DbContext.Orders.Select(o => new { Id = o.Id, Name = o.Name, Description = o.Description });
while the other service method does something like:
return DbContext.Orders.Select(o => o);
I'm not sure how your application is architected, but this may be a way around creating 100's of POCO's.
Hope this helps! Good luck.
You could pass in a selector Func that returns dynamic:
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector) { ... }
I'm not sure how you are accessing data, but the following shows how this would work using a List<T>:
class Program
{
static void Main(string[] args)
{
var service = new Service();
var orderNames = service.GetOrders(o => new { o.Name });
foreach (var name in orderNames)
Console.WriteLine(name.Name);
Console.ReadLine();
}
}
public class Service
{
private List<Order> _orders = new List<Order>
{
new Order { Id = 1, Name = "foo", Description = "test order 1", Amount = 1.23m },
new Order { Id = 2, Name = "bar", Description = "test order 1", Amount = 3.45m },
new Order { Id = 3, Name = "baz", Description = "test order 1", Amount = 5.67m }
};
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector)
{
return _orders.Select(selector);
}
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
}
The use of nullable values is a good solution, however it has the downside you have no way to matk required fields. That is you cannot use a required attribute on any property. So if there is field that is obligatory in some views you have no way to represent it.
If you don't need required fileds validation this is ok. Otherwise, you need a way to represent which fileds are actually used, and then to write a custom validation provider.
A simple way to do this is to use a "Mask" class with the same property names of the original class, but with all fields boolean: a true values means the field is in use.
I used a similar solution in a system where the properties to be shown are configured in a configuration files...so it was the unique option for me since I had no possibility to represent all combination of properties. HOWEVER, I used the "Mask" class also in the View, so I was able to do all the job with just one View..with a lot of ifs.
Now if your 150 service methods and probably about 150 Views...are all different, then maybe it is simpler to use also several classes ...that is in the worst case 150 classes..the extra work to write them is negligible if compared to the effort of preparing 150 different Views.
However this doesnt mean you need 150 POCO classes. You might use an unique POCO class that is copied into an adequate class just into the presentation Layer. The advantage of this approach is that you can put different validation attributes on the various classes and you don't need to write a custom Validation provider.
Return the entire POCO with nullable types as mentioned by #sbolm. You can then create a ViewModel per MVC page view that receives a model with the specific properties it needs. This will take more performance (insignificant) and code, but it keeps your service layer clean, and keeps your views "dumb" in that they are only given what they need and have no direct relation to the service layer.
I.e. (example class from #sbolm)
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
// MVC View only needs to know the name and description, manually "map" the POCO properties into this view model and send it to the view
class OrderViewModel {
public string Name {get;set;}
public string Description {get;set;}
}
I would suggest that instead of modifying the models or creating wrapper models, you have to name the service methods such that they are self-explanatory and reveals the consumer what they returns.
The problem with the nullable approach is it makes the user to feel that the property is not required or mandatory and they try inserting instances of those types without setting those properties. Is it won't be bad having nullables every-where?
It won't be a good approach to change the domain models since all you want is just to populate some of the properties instead of that you create service with names and descriptions that are self-explanatory.
Take the Order class itself as the example, say one service method returns the Order with all the items and the other one returns only the details of the Order but not the items. Then obviously you may have to create two service methods GetOrderItems and GetOrderDetail, this sounds so simple, yes it is! but notice the service method names itself tells the client what it is going to return. In the GetOrderDetail you can return an empty items or null (but here I suggest a null) that doesn't matter much.
So for new cases you don't need to frequently change the models but all you got to do is add or remove the service methods and that's fine. Since you are creating a service you can create a strong documentation that says what method does what.
I would not performance optimize this to much unless you realy get performance problems.
I would only distinguish between returning a flat object and an object with a more complete object graph.
I would have methods returning flat objects called something like GetOrder, GetProduct.
If more complete object graphs are requested they would be called : GetOrderWithDetails.
Do you use the POCO classes for the typed views? If yes: try to make new classes that serve as dedicated ViewModels. These ViewModels would contain POCO classes. This will help you keeping the POCO classes clean.
To expand on the nullable idea, you could use the fluentvalidation library to still have validation on the types dependent on whether they are null or not. This would allow you to have a field be required as long as it was not null or any other validation scheme you can think of. Example from my own code as I had a similar requirement:
Imports FluentValidation
Public Class ParamViewModelValidator
Inherits AbstractValidator(Of ParamViewModel)
Public Sub New()
RuleFor(Function(x) x.TextBoxInput).NotEmpty.[When](Function(x) Not (IsNothing(x.TextBoxInput)))
RuleFor(Function(x) x.DropdownListInput).NotEmpty.[When](Function(x) Not (IsNothing(x.DropdownListInput)))
End Sub
End Class
I'm following Steve Sanderson's example from this ASP.NET MVC book on creating a model by hand instead of using diagramming tools to do it for me. So in my model namespace I place a class called MySystemModel with something like the following in it
[Table(Name="tblCC_Business")]
public class Business
{
[Column(IsPrimaryKey=true, IsDbGenerated=false)]
public string BusinessID { get; set; }
// this is done because Business column and Business have interfering names
[Column(Name="Business")] public string BusinessCol { get; set; }
}
This part of it is all fine. The problem however is returning multiple result sets from a stored procedure, but mixing and matching SQL with LINQ modelling. We do this because the LINQ to SQL translation is too slow for some of our queries (there's really no point arguing this point here, it's a business requirement). So basically I use actual SQL statements along with my LINQ models in my "repository" like so:
public IEnumerable<MyType> ListData(int? arg)
{
string query = "SELECT * FROM MyTable WHERE argument = {0}";
return _dc.ExecuteQuery<MyType>(query, arg);
//c.GetTable<MyType>(); <-- this is another way of getting all data out quickly
}
Now the problem I'm having is how to return multiple result sets as I'm not extending DataContext, like so:
public ContractsControlRepository()
{
_dc = new DataContext(ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString());
}
This link describes how multiple result sets are returned from stored procedures.
[Function(Name="dbo.VariableResultShapes")]
[ResultType(typeof(VariableResultShapesResult1))]
[ResultType(typeof(VariableResultShapesResult2))]
public IMultipleResults VariableResultShapes([Parameter(DbType="Int")] System.Nullable<int> shape)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), shape);
return ((IMultipleResults)(result.ReturnValue));
}
So how do I turn this into something that can be used by my repository? I just need to be able to return multiple result sets from a repository which contains DataContext, and doesn't extend it. If you copied and pasted the previous extract into a repository like I've got it will just state how ExecuteMethodCall isn't available, but that's only available if you extend DataContext.
Resources
Guy Berstein's Blog
Every time I ask a question that has been hindering me for days on end I end up finding the answer within minutes. Anyway, the answer to this issue is that you have to extend DataContext in your repository. If like me you're worried about having to specify the connection string in every single controller then you can change the constructor in the repository class to something like this:
public ContractsControlRepository()
: base(ConfigurationManager.ConnectionStrings["AccountsConnectionString"].ToString()) { }
This way when you instantiate your repository the connection is set up for you already, which gives you less to worry about, and actually centralizes specifying the connection string. Extending DataContext also means you have access to all of the protected methods such as ExecuteMethodCall used for calling stored procedures and bringing back, if you will, multiple result sets.