Leaking Quriable objects to upper layers - entity-framework

i have an application that is flexible, that the user can:
filter by any field
sort by any multiple of fields.
and because it will run in ASP.Net Site + some Xamarin C# Apps, i will also have paging in it.
For network performance, it will send projection on the required fields that will be shown.
So if i include in each "Service" method, a parameter "UQueryConstraints", that can send filter expression + oderBy expression + page numbers + Projection of the fields, to be used by the Repository, which will apply it to the DBContext, is this is going to be considered a Data leak to the domain services or not?
as seen in this Pic:
http://1drv.ms/1Ngi3Kn
e.g.:
notice:
"UQueryConstraints", it will not leak any "IQueryable".
The "AmbientDbContextLocator", from:
<http://mehdi.me/ambient-dbcontext-in-ef6/>
<https://github.com/mehdime/DbContextScope>
public class UIView
{
public static void Display()
{
object constraintsB = new UQueryConstraints<Car>().Filter(x => x.carNo <= 6).SortBy(x => x.eName).Page(1, 5);
//.Projection( field1, field2, field3)
Debug.WriteLine("---------------test CarModel -------------------");
CarModel carModel1 = new CarModel();
carModel1.printCars(constraintsB);
}
}
public class CarModel
{
private CarService _carService = new CarService();
void printCars(UQueryConstraints<Car> constraints)
{
foreach ( c in _carService.getCarsList("", constraints)) {
Debug.WriteLine("Reading from converted back: aName =" + c.aName + ", eName = " + c.eName);
}
}
}
public class CarService
{
public IList<Car> getCarsList(string Text, UQueryConstraints<Car> constraints)
{
object dbContextScopeFactory = new DbContextScopeFactory();
object ambientDbContextLocator = new AmbientDbContextLocator();
using (dbContextScope == dbContextScopeFactory.Create()) {
//after creating the Scope:
//1. create the repository
//2. call repository functions
object carRep = new CarRepository(ambientDbContextLocator);
return carRep.getCarsList("", constraints);
}
}
}
public class CarRepository : URepositoryFramwork.URepository
{
public CarRepository(IAmbientDbContextLocator contextLocator)
{
base.New(contextLocator);
}
public IList<Car> getCarsList(string Text, UQueryConstraints<Car> constraints)
{
object query = this.DataSet.Where(constraints.FilterExpression);
//.Select(constraints._projection2)
IList<Car> items;
if (constraints == null) {
items = query.ToList();
} else {
items = constraints.ApplyTo(query).ToList();
}
return items;
}
}
Regards.

Here are few points.
You don't need UQueryConstraints at all and you don't need to do any filtering in the UI at all.
I'd ague that the model is something that needs to be returned from the service so I wouldn't create CarModel in the UI layer and then pushed values to it, it doesn't make sense to me.
I'd have a method on the service that request some data and then returns it in some shape or form to the UI.
I'd inject the service to UIView.
I don't understand why there's so much noise around the context and why do you create it in getCarsList it seems like getCarList should be a class called RequestCars and both the repository and the service should be removed in favor of something like depicted in the command pattern.
I don't like the whole abstraction here at all, seems like over engineering to me and who says that IQueryable should be abstracted? it's like abstracting language/framework features whereas you should abstract domain features and only when necessary.
Abstracting 3rd-party frameworks can be fine to some extent but this isn't one of these cases.

Related

Expected default behavior for Grails RESTful mapping to Nested Resources

I have my Grails Domain classes annotated with #Resource with the uri specifications in UrlMappings where I declare the resource nesting. But even though according to https://docs.grails.org/latest/guide/theWebLayer.html#restfulMappings it seems that just declaring this the right way, I should have the correct behavior that I wanted, which is that a URL pattern such as /nesting/1/nested will list the nested domain that belonged to the nesting domain with ID 1, the observed behavior is that it just lists out all nested domain objects.
So for that, my workaround is to have a controller implemented that overrides the listResources to filter the nested domain by the nesting domain. But what's weird to me is why I even have to do that at all. The documentation said it defaults to the index action but said index action seems to just behave as if it's the index() of nested (without taking nesting into account).
My domain entities are WeightSensor:
#Resource(formats = ['json', 'xml'])
class WeightSensor extends Sensor<WeightData>
{
Set<WeightData> data
static constraints = {
}
}
its superclass Sensor
#Resource(formats = ['json', 'xml'])
class Sensor<T extends SensorData>
{
Set<T> data
static hasMany = [data: SensorData]
String name
static constraints = {
name unique: true
}
}
and WeightData
class WeightData extends SensorData
{
Float weight
static constraints = {
weight nullable: false
}
}
and its superclass SensorData
class SensorData
{
#BindingFormat('yyyy-MM-dd HH:mm:ss.S') // 2019-07-11 22:00:28.909
Date timestamp
static belongsTo = [sensor: Sensor]
static constraints = {
timestamp nullable: false
}
}
In my UrlMappings I have the following:
"/sensor/weight"(resources: 'weightSensor') {
"/data"(resources: "weightData")
}
My WeightDataController extends from a SensorDataController:
class WeightDataController extends SensorDataController<WeightSensor, WeightData>
{
#SuppressWarnings("GroovyUnusedDeclaration")
static responseFormats = ['json', 'xml']
WeightDataController()
{
super(WeightData, WeightSensor, "weightSensorId")
}
}
And SensorDataController in turn extends RestfulController, and overrides the listAllResources method as below.
import grails.rest.RestfulController
class SensorDataController<S extends Sensor, T extends SensorData> extends RestfulController<T>
{
String idProperty
Class<S> sensorType
#SuppressWarnings("GroovyUnusedDeclaration")
static responseFormats = ['json', 'xml']
protected SensorDataController(Class<T> dataType, Class<S> sensorType, String idProperty)
{
super(dataType)
this.idProperty = idProperty
this.sensorType = sensorType
}
#Override
protected List<T> listAllResources(Map params)
{
Long sensorId = params.get(idProperty) as Long
if (sensorId)
{
resource.withCriteria() {
eq 'sensor.id', sensorId
maxResults params.max ?: 10
firstResult params.offset ?: 0
} as List<T>
}
else
{
super.listAllResources(params)
}
}
}
Note because in order for me to have my WeightDataController class be used, I needed to remove the #Resource on top of WeightData domain entity above, another nice little gem of wisdom I had to discover with trial and error.
I can probably blame this on the fact that the documentation for nested resources seems a bit open to interpretation. But when we see in the documentation a URL like GET books/${bookId}/authors, doesn't that look like it should return the list of Author objects that belongs to the Book instance IDed by bookId?
I know that I'm not alone as I did find this online of someone asking the same question I have - https://gist.github.com/mnellemann/7cfff1c721ef32f0be6c63574795f795 but no one answered them either. I also came across another SO post nested RESTful resources that was abandoned 5 years ago as well.
But 3 people having the same question and no one responding to our questions (I asked mine on the Grails Slack community) usefully because there is a work-around is not acceptable. At the risk of having my question taken down for a slew of different reasons, I question the usefulness of even having the grails nested resource URL mapping in the first place because I could have done everything manually myself without having to "declare" such a nesting in UrlMappings.
In closing, what I'm trying to find out is whether or not there's more "configuration" I need to do to get Grails nested Resources to behave in the way that I expected, which is how the documentation painted, correctly. Because just doing what was described doesn't get me that.

Search implementation for a RESTful interface on Grails

I'm building a RESTful interface on a Grails 2.1.1 application. How should I implement search operations? I don't want to repeat huge amounts of code, which my current thinking would require.
The server structure is quite normal Grails-MVC: domain classes represent data, controllers offer the interface and services have the business logic. I use command objects for data binding in controllers but not on service methods. The client is a web UI. My goal is to have search URLs like this:
/cars/?q=generic+query+from+all+fields
/cars/?color=red&year=2011
(I'm aware of the debate on the RESTfulness of this kind of URLs with query strings: RESTful URL design for search. While I think this is the best model for my purpose, I'm open to alternatives if they make the API and the implementation better.)
As you can see from the code examples below my problem is with the second kind of URL, the field-specific search. In order to implement this kind of search operation for several domain classes with lots of fields my method signatures would explode.
There probably is a "Groovy way" to do this but I'm still a bit of a n00b in finer Groovy tricks :)
Domain:
class Car {
String color
int year
}
Controller:
class CarsController {
def carService
def list(ListCommand cmd) {
def result
if (cmd.q) {
result = carService.search(cmd.q, cmd.max, cmd.offset, cmd.order, cmd.sort)
}
else {
result = carService.search(cmd.color, cmd.year, cmd.max, cmd.offset, cmd.order, cmd.sort)
}
render result as JSON
}
class ListCommand {
Integer max
Integer offset
String order
String sort
String q
String color // I don't want this field in command
int year // I don't want this field in command
static constraints = {
// all nullable
}
}
// show(), save(), update(), delete() and their commands clipped
}
Service:
class CarService {
List<Car> search(q, max=10, offset=0, order="asc", sort="id") {
// ...
}
List<Car> search(color, year, max=10, offset=0, order="asc", sort="id") {
// ...
}
}
UrlMappings:
class UrlMappings {
static mappings = {
name restEntityList: "/$controller"(parseRequest: true) {
action = [GET: "list", POST: "save"]
}
name restEntity: "/$controller/$id"(parseRequest: true) {
action = [GET: "show", PUT: "update", POST: "update", DELETE: "delete"]
}
}
}
You can get all this parameters from params, like:
result = carService.search(params.color, params.year as Integer, cmd.max, cmd.offset, cmd.order, cmd.sort)
All values of params map are strings, so you should convert it to appropriate data structures in controller (and it's better to check that params.year is actual number)
Update
If you don't want to writer field names, you can pass it as a Map:
resutl = carService.search(params)
where
List<Car> search(Map params)

Unit of Work, LazyLoading Disabled, Generic Repository, IncludeMultiple<T>, Http 500 error

I have a Vehicle with an association to Model, Model has an association to Make.
Here is my Generic Repository as pertaining to associations as LazyLoadingEnabled = false in my project:
public IQueryable<T> IncludeMultiple<T1>(params Expression<Func<T, object>>[] associations) where T1 : class
{
var source = (IQueryable<T>)DbContext.Set<T>();
if (associations != null)
{
foreach (Expression<Func<T, object>> path in associations)
source = DbExtensions.Include<T, object>(source, path);
}
return source;
}
In my api controller, I am using Unit of work pattern. Here is my GetAll method:
public IEnumerable<Vehicle> GetAll()
{
var vehicles = Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel).ToList();
return vehicles;
}
Everything works fine and Json retrieves the Vehicle class data as well as the related VehicleModel class data.
However, Vehicle has no direct association to VehicleMake, only VehicleModel does. Now, if my GetAll method has this:
public IEnumerable<Vehicle> GetAll()
{
var vehicles = Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel, c => c.VehicleModel.VehicleMake).ToList();
return vehicles;
}
while I see in debug that vehicles does indeed have the vehicles and their relevant VehicleModel and VehicleMake data, it returns a Http 500 error in Fiddler.
Update:
Added another association in Vehicle called "Test", with the GetAll method being:
(c => c.VehicleModel, c => c.Test)
No error, all data was returned via fiddler. So, it appears that a "Non-direct association" (ie Vehicle -> VehicleMake) is the cause of the error.
Question:
What would be the correct way to retrieving the relevant Vehicle data and its associated classes' data and return it to Json while not getting a Http 500 error?
*SOLVED *
This works:
public HttpResponseMessage GetAll()
{
var vehicles = from data in Uow.VehicleRepository.IncludeMultiple<Vehicle>(c => c.VehicleModel,c => c.VehicleModel.VehicleMake)
select new
{
VehDesc = data.Description,
VehVIN = data.VIN,
VehTransmissionType = data.TransmissionType,
VehFuelType = data.FuelType,
VehYear = data.Year,
VehMileage = data.Mileage,
VehCylinderSize = data.CylinderSize,
VehEngineSize = data.EngineSize,
VehVehicleModel = data.VehicleModel.Name,
VehMakeName = data.VehicleModel.VehicleMake.Name
};
return Request.CreateResponse(HttpStatusCode.OK, vehicles);
}
Basically,
1. I used an HttpResponseMessage as my return type;
2. I used projection to create an anonymous type;
Why did I have to do this?
As near as I can tell, the issue centered on JSON receiving a "circular" return with VehicleModel and VehicleMake. That is, VehicleModel had a association to VehicleMake and VehicleMake has a collection of VehicleModels. When I looked in my debug code I could see a cascade of VehicleModel to VehicleMake to VehicleModel, etc, etc, etc, so to me that meant it was circular.
If anyone knows a better way w/o using anonymous type nor removing the virtual keyword from my navigation properties, I would certainly like to know it. But this does truly work.
FinalNote: Be sure NOT to use the model's property names in anonymous type, ie replace property "TransmissionType" with something like "VehTransmissionType".

Entity Framework and Entity Tracker Problems

If I run the following code it throws the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
public void Save(Category category)
{
using(var db = new NorthwindContext())
{
if(category.CategoryID == 0)
{
db.AddToCategorySet(category);
}
else
{
//category.RemoveTracker();
db.Attach(category);
}
db.SaveChanges();
}
}
The reason is of course that the category is sent from interface which we got from GetById method which already attached the EntityChangeTracker to the category object. I also tried to set the entity tracker to null but it did not update the category object.
protected void Btn_Update_Category_Click(object sender, EventArgs e)
{
_categoryRepository = new CategoryRepository();
int categoryId = Int32.Parse(txtCategoryId.Text);
var category = _categoryRepository.GetById(categoryId);
category.CategoryName = txtUpdateCategoryName.Text;
_categoryRepository.Save(category);
}
I'm still learning Entity Framework myself, but maybe I can help a little. When working with the Entity Framework, you need to be aware of how you're handling different contexts. It looks like you're trying to localize your context as much as possible by saying:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
...
}
}
... within your data access method. Did you do the same thing in your GetById method? If so, did you remember to detach the object you got back so that it could be attached later in a different context?
public Category GetById(int categoryId)
{
using (var db = new NorthwindContext())
{
Category category = (from c in db.Category where Category.ID == categoryId select c).First();
db.Detach(category);
}
}
That way when you call Attach it isn't trying to step on an already-attached context. Does that help?
As you pointed out in your comment, this poses a problem when you're trying to modify an item and then tell your database layer to save it, because once an item is detached from its context, it no longer keeps track of the changes that were made to it. There are a few ways I can think of to get around this problem, none of them perfect.
If your architecture supports it, you could expand the scope of your context enough that your Save method could use the same context that your GetById method uses. This helps to avoid the whole attach/detach problem entirely, but it might push your data layer a little closer to your business logic than you would like.
You can load a new instance of the item out of the new context based on its ID, set all of its properties based on the category that is passed in, and then save it. This costs two database round-trips for what should really only need one, and it isn't very maintainable.
You can dig into the context itself to mark the Category's properties as changed.
For example:
public void Save(Category category)
{
using (var db = new NorthwindContext())
{
db.Attach(category);
var stateEntry = db.ObjectStateManager.GetObjectStateEntry(category);
foreach (var propertyName in stateEntry.CurrentValues.DataRecordInfo.FieldMetadata.Select(fm => fm.FieldType.Name)) {
stateEntry.SetModifiedProperty(propertyName);
}
db.SaveChanges();
}
}
This looks a little uglier, but should be more performant and maintainable overall. Plus, if you want, you could make it generic enough to throw into an extension method somewhere so you don't have to see or repeat the ugly code, but you still get the functionality out of it.

EFPocoAdapter -- PopulatePocoEntity has null PocoEntity

I'm trying EF with the EFPocoAdapter for the first time. I have a relatively simple TPH scenario with one table and two types, each inheriting from an abstract base class.
My model validates through EdmGen, and my PocoAdapter.cs and xxxEntities.cs files generate fine as well. (well, actually, there are some namespace problems that I'm currently tweaking by hand until we figure out where to go next.)
When I run a simple test to retrieve data:
using (CINFulfillmentEntities context = new CINFulfillmentEntities())
{
// use context
var alerts = from p in context.Notifications.OfType<Alert>()
select p;
foreach (var alert in alerts)
{
Assert.IsNotNull(alert);
}
}
I get an error in the PocoAdapter class, claiming that PocoEntity is null is the following method inside my base class's adapter:
public override void PopulatePocoEntity(bool enableProxies)
{
base.PopulatePocoEntity(enableProxies);
PocoEntity.Owner = _Owner.CreatePocoStructure();
if (!(PocoEntity is IEntityProxy))
{
}
}
Any ideas from anyone?
So, after a little more debugging, I think this is related to proxies. Inside PocoAdapterBase we have the following method:
protected PocoAdapterBase(TPocoClass pocoObject)
{
_context = ThreadLocalContext.Current;
bool allowProxies = false;
if (_context != null)
{
allowProxies = _context.EnableChangeTrackingUsingProxies;
}
_pocoEntity = pocoObject ?? (TPocoClass)(allowProxies ? CreatePocoEntityProxy() : CreatePocoEntity());
Init();
InitCollections(allowProxies);
RegisterAdapterInContext();
}
The line that sets _pocoEntity calls CreatePocoEntityProxy, which returns null.
More info as I find it.