Getting the final projection from a wrapped IQueryable - c#

I'm not really sure how to express what I'm trying to achieve without showing some pseudo-code to the effect -
Assuming the following DTO is defined:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
We have 2 different custom IQueryable<T> classes defined:
public class InnerQueryable<T> : IQueryable<T>
{
// ...
}
public class OuterQueryable<T> : IQueryable<T>
{
public OuterQueryable(IQueryable<T> inner)
{
// Assign `inner` to a local variable to be used in `IQueryable<T>` impl.
// ...
}
// ...
}
NOTE: OuterQueryable<T> is designed to extend the behavior of any other IQueryable<T> type by wrapping it.
And a rather naive extension method to allow OuterQueryable<T> implementations to be created simply:
public static IQueryable<T> ToOuterQueryable<T>(this IQueryable<T> inner /*, ... */)
{
// Assume `OuterQueryable<T>` has a constructor that takes another `IQueryable<T>`.
return new OuterQueryable<T>(inner /*, ... */);
}
Given an expression as shown below, is there any way for the InnerQueryable<T> instance to find out which specific properties are selected once the query is wrapped by OuterQueryable<T>?
InnerQueryContext.AsQueryable<Person>().Where(p => p.Age > 30)
.ToOuterQueryable().Select(p => new
{
p.FirstName,
p.LastName
};
Is there anyway for InnerQueryable<T> to know that the query built on
OuterQueryable<T> returned only Person.FirstName and Person.LastName?
If it helps to show the context, I have a WCF data service that returns our internal entity, but I need the ability to know which specific members of the internal entity were returned from the service. WCF DS defines the OuterContext<T> in this case and I haven't identified a way to intercept the response post-projection to tell me what I'm looking for.
Any ideas would be welcome.
UPDATE: What are InnerQueryable<T> and OuterQueryable<T>?
The answer to that is fairly involved if you aren't familiar with the architecture of WCF Data Services, but here it goes:
In WCF Data Services, a service exposes IQueryable<T> properties to a DataServiceProvider implementation (i.e. EntityFrameworkDataServiceProvider, ReflectionDataServiceProvider, or a custom DataServiceProvider implementation that implements the necessary interface(s)).
These core IQueryable<T> properties act as the foundation of resources exposed through the service, and are built upon using the composable nature of LINQ queries. A simple example using the Person entity above would look like:
public class SimpleContext
{
public IQueryable<Person> People
{
get
{
return new[] {
new Person { FirstName = "George", LastName = "Jetson", Age = 43 },
new Person { FirstName = "Elroy", LastName = "Jetson", Age = 7 }
}.AsQueryable();
}
}
}
This SimpleContext would then be referenced by a simple data service implementation:
public class SimpleDataService : DataService<SimpleContext>
{
// InitializeService method and others...
}
Now when I query the data service passing a projection:
http://localhost/SimpleDataService/People()?$select=FirstName,LastName
The framework will take the IQueryable<Person> returned from SimpleDataContext.People and pass it through an internal IQueryProvider/IQueryable implementation that understands how to generate an expression tree from the query string parameters and then compose another query using the IQueryable<Person> as its source.
Conceptually though, my original question above describes how to replicate the behavior without having to worry about all of the WCF data services stuff.

I still don't quite understand why would WCF DS need that OuterQueryable. What it needs to do is to parse the query and then call your InnerQueryable based on that.
If there indeed is some kind of wrapper around your InnerQueryable, then it's entirely up to that wrapper to decide what your wrapper queryable will be able to see.
Consider two trivial implementations of the wrapper: if the wrapper simply forwards each method call to the wrapped object, then you will be able to see everything directly. On the other hand, if the wrapper doesn't do anything at all, then there is no way for you to observe anything at all.

Related

Hot Chocolate: Transforming results from [UseFiltering] Query

I'm looking to use Hot Chocolate's Filtering to query against one data type; and then transform that filtered output to another type before returning it as an IQueryable. But I can't seem to find anyway to capture the filter input to start my transform.
Here's an example of what I'm trying to accomplish:
Given the data classes
public class TypeA
{
public string Foo { get; set; }
}
public class TypeB
{
public string Fizz { get; set; }
public string Buzz { get; set; }
}
I want to be able to create a query endpoint like
public class Query
{
[UseDbContext(typeof(DbContext))]
[UseFiltering(typeof(TypeA))]
public IQueryable<TypeB> GetTypeB(
[ScopedService] DbContext context,
[SomeAttributeToCaptureTheFilter] Filter filter) // <- this is the line I'm trying to figure out
{
IQueryable<TypeA> filteredTypeAs = context.TypeA.Filter(filter); // .Filter() doesn't exist, its just for example.
IQueryable<TypeB> filteredTypeBs;
/* Complex transformation logic that populates 'filteredTypeBs'
* requiring the 'filteredTypeAs' and additional Data from
* the database to complete. */
return filteredTypeBs;
}
}
Against which, I can use a GraphQL Query like the following
query {
typeB(where: { foo: { eq: "bar" } }) {
fizz
buzz
}
}
where: { foo: { eq: "bar" } } Being the filter against TypeA, and the
typeB {
fizz
buzz
}
pulling the content from the transformed TypeB.
Using [UseFiltering(typeof(TypeA))] does work, It sets up the schema to act as I want.
What I'm looking for is something to the effect of the line [SomeAttributeToCaptureTheFilter] Filter filter. Just some way of capturing the filter and applying it to the data within the DbContext.
I will also say I'm very new to GraphQL in general, so how I'm approaching this problem may be entirely wrong. Any advice would be helpful.
Answering my own question for anyone who may stumble upon this in the future.
The answer was in the HotChocolate.Data package. It contains Filter extensions for IQueryable<T> and IEnumerable<T>; that allow you to run the filter inline by passing an IResolverContext. I couldn't find references to any of this in the documentation, I came across it in an example about data aggregation: https://github.com/ChilliCream/hotchocolate/issues/924#issuecomment-921793977
This is essentially what my final query method looked like:
using HotChocolate.Data;
using HotChocolate.Data.Filters.Expressions;
public class Query
{
[UseDbContext(typeof(DbContext))]
[UseFiltering(typeof(TypeA))]
public IQueryable<TypeB> GetTypeB(
[ScopedService] DbContext context,
IResolverContext resolverContext)
{
IQueryable<TypeA> filteredTypeAs = context.TypeA.Filter(resolverContext);
IQueryable<TypeB> filteredTypeBs;
/* Complex transformation logic that populates 'filteredTypeBs'
* requiring the 'filteredTypeAs' and additional Data from
* the database to complete. */
return filteredTypeBs;
}
}
I know my example's a bit esoteric, but the point of this is that it opens up access to a filtered version of the results within the query method itself. This allows for a whole world of possibilities when it comes to data aggregation/manipulation; while still taking advantage of the HotChocolate's built in functionality.
As a side note there also appears to be a Sort extension, which is the equivalent for [UseSorting].

Update all Fields passed in object without using replace

I'm writing a wrapper around certain functions of mongodb to enforce certain buisiness policies (such as having a last modified date, a document version &c). These extra fields will not appear in the model and will be irrelevant and transparent to the person implementing against this library. This library will be generic.
Therefore using replaceOne is out of the question.
What I would like is some way of passing all fields in a person passed object to the Update builder - so I can use .Set/.Inc accordingly to add the other fields.
An example to demonstrate what I want is below:
public static async Task UpdatePerson(string name, Person person)
{
var client = new MongoClient("mongodb://localhost:27017");
IMongoDatabase db = client.GetDatabase("test");
IMongoCollection<Person> collection = db.GetCollection<Person>("people");
var query = Builders<Person>.Filter
.Eq("name", name);
var update = Builders<Person>.Update
//Something here - how do I pass my person's properties?
.Set("lastModified", DateTime.Now)
.Inc("version",1);
await collection.UpdateOneAsync(query, update );
}
//--
//In real life this'll work for other types, this is for demonstration only
public class Person
{
public string name {get;set;}
public string surname {get;set;}
}
So how can I go about this, without, for instance, looping through properties using Reflection?
Not sure if you are able to do this but the Mongodb Driver provides something called [BsonExtraElements].
public class Person
{
public string name {get;set;}
public string surname {get;set;}
[BsonExtraElements]
public Dictionary<string,object> AdditionalFields { get; set; }
}
What will happen is that anything that cant be serialized to the model will be filled into that dictionary, no matter the type. You can add to it as well and remove.
This will add no additional overhead to your database, The only downside to this is that querying this dictionary is somewhat not a great experience as you may need to cast specific keys to their relevant expected types.
If this is not viable I suggest the BSON approach recommended by Simon.

C# + MongoDB - ObjectId without using MongoDB DataTypes/Attributes

Using MongoDB as my data store makes me to have ObjectID type as primary key by Default. It also can be changed by using Guid with [BsonId] attribute. Which is also defined in MongoDB C# Driver library. I would like to have my Entities independent from Data layer.
Can I just use name Id for the property to identify primary key? What else I can try?
You can use BsonClassMap instead of using attributes to keep your classes "clean".
// 'clean' entity with no mongo attributes
public class MyClass
{
public Guid Id { get; set; }
}
// mappings in data layer
BsonClassMap.RegisterClassMap<MyClass>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id).SetIdGenerator(CombGuidGenerator.Instance);
});
OPTION 1: Stick with BsonId and use the Facade Pattern
The [BsonId] property is what you'd use to indicate that the _id property should be linked to a specific property. There isn't a way around that (short of ignoring _id entirely in your crud operations which seems like a bad idea).
So, if you want to separate your "entity" object from your "data layer" then just use a poco class.
-- Use a poco class as a substitute for a record. That class is only for data storage: a quick way to get data in/out of mongo, and a great alternative to working with bson documents.
-- Use a facade on top of that poco class for your entity layer. I don't find it useful to re-invent the wheel, so I typically ask our devs have the entity interface inherit the data-layer (poco) interface, but you can do it however you'd like
Breaking up a sample MyObject class
IMyObjectRecord (declared at the dal and contains only properties and mongo-specific attributes)
IMyObject:IMyObjectRecord (declared at the entity level and may include added properties and methods)
MyObjectRecord:IMyObjectRecord (declared inside the dal, contains mongo-specific attributes. Could be declared internal if you wanted to be really strict about separation).
MyObject:IMyObject (could be, for example, a facade on top of the IMyObjectRecord class you pull from the dal).
Now - you get all the benefits of the facade, and you have a hard-coded link between the properties BUT, you get to keep Bson attributes contained in your dal.
OK, fine. But I really really really HATE that answer.
Yeah. I can accept that. OK, so how about a Convention Pack? If you ABSOLUTELY PROMISE that you'll call your Id's "Id" and you SWEAR that you'll type them as strings (or -- use some other convention that is easy to identify), then we could just use a convention pack like the one I stole from here
namespace ConsoleApp {
class Program {
private class Foo {
// Look Ma! No attributes!
public string Id { get; set; }
public string OtherProperty { get; set; }
}
static void Main(string[] args) {
//you would typically do this in the singleton routine you use
//to create your dbClient, so you only do it the one time.
var pack = new ConventionPack();
pack.Add(new StringObjectIdConvention());
ConventionRegistry.Register("MyConventions", pack, _ => true);
// Note that we registered that before creating our client...
var client = new MongoClient();
//now, use that client to create collections
var testDb = client.GetDatabase("test");
var fooCol = testDb.GetCollection<Foo>("foo");
fooCol.InsertOne(new Foo() { OtherProperty = "Testing", Id="TEST" });
var foundFoo = fooCol.Find(x => x.OtherProperty == "Testing").ToList()[0];
Console.WriteLine("foundFooId: " + foundFoo.Id);
}
//obviously, this belongs in that singleton namespace where
//you're getting your db client.
private class StringObjectIdConvention : ConventionBase, IPostProcessingConvention {
public void PostProcess(BsonClassMap classMap) {
var idMap = classMap.IdMemberMap;
if (idMap != null && idMap.MemberName == "Id" && idMap.MemberType == typeof(string)) {
idMap.SetIdGenerator(new StringObjectIdGenerator());
}
}
}
}
}
What's a Convention Pack
It's a little set of mongo "rules" that get applied during serialize/deserialize. You register it once (when you setup your engine). In this case, the sample pack is telling mongo "if you see a field called 'Id', then save it as a string to _id, please."
These can get really complex and fun. I'd dig into convention packs if you really really really hate the other approach. It's a good way to force all your mongo "attribute driven" logic into one self-contained location.
I have stumbled on the same problem myself, and I didn't want to have mongo attributes inside my classes.
I have created a small wrapper example to show how I save and find elements without having an Id property on the data classes of my business logic.
The wrapper class:
public static class Extensions
{
public static T Unwrap<T>(this MongoObject<T> t)
{
return t.Element;
}
}
public class MongoObject<T>
{
[BsonId]
private ObjectId _objectId;
public T Element { get; }
public MongoObject(T element)
{
Element = element;
_objectId = new ObjectId();
}
}
I have also added an extension method to easily unwrap.
Saving an element is simple
public void Save<T>(T t)
{
_collection.InsertOne(new MongoObject<T>(t));
}
To find an element we can do a linq-like query:
Say we have a data class:
public class Person
{
public string Name { get; set; }
}
then we can find such an element by
public Person FindPersonByName(string name)
{
return _collection.AsQueryable().FirstOrDefault(
personObject => personObject.Element.Name == name).Unwrap();
}
We can also generalize by making MongoObject implement IQueryable<T> and this would make the use of the wrapper even more convenient
If i understand correctly. You want to put your entity to other layer without attribute.
I think you can try this
public object Id { get; set; }
after that you can put your Id which is coming from mongodb without attribute

Effects of returning a self reference from an instance method in C#

Let's say I have an interface called IConvertableModel and it helps me to convert some MVC models to/from DTO objects as shown below:
public class DisplayEditModel : IConvertableModel<Display>
{
[HiddenInput(DisplayValue = false)]
public int ObjectId { get; set; }
[StringLength(255)]
public string Description { get; set; }
public Display ToDto()
{
return new Display
{
Description = Description,
ObjectId = ObjectId,
};
}
public void SetFromDto(Display dto)
{
Description = dto.Description;
ObjectId = dto.ObjectId;
}
}
But there is one problem with this approach and that is it doesn't allow me do this :
var dto = _dtoRepository.GetFirstDto();
return new DisplayEditModel().SetFromDto(dto);
Instead I should do the following:
var dto = _dtoRepository.GetFirstDto();
var model = new DisplayEditModel();
model.SetFromDto(dto);
return model;
and this is adding extra two lines of code and little bit complexity in the long run.
What I am thinking is to convert SetFromDto method to something like this:
public DisplayEditModel SetFromDto(Display dto)
{
Description = dto.Description;
ObjectId = dto.ObjectId;
return this;
}
I think the benefit of this code is obvious but I also like to learn whether this harms code readability and leads to unexpected results for developers in the long run and if you think anything else, what would you recommend.
Note: Because of the interfaces reasons, I am not thinking to implement a constructor method.
A few thoughts, to begin with:
Adding lines of code is not the same as adding complexity. Having three statements, where each does a simple operation, is not necessarily harder to maintain or understand than a single statement with three operations inside of it.
When a method that begins with Set..., programmers will automatically assume that some stateful values of the target object are going to be changed by this method. It is rare for Set methods to have a return value. Property setters in C# actually "return" the original value passed into them, so you can chain setters:
int i = foo.A = 2;
So the precedent is generally against returning "this" from a set method specifically.
Chaining in general is most useful/desired when you're expecting several operations to be performed, one after the other. For example, C# provides nice initialization syntax so you can "chain" a bunch of different property setters on the same object:
var foo = new Foo { A = 1, B = 2 };
You can see how chaining is fulfilling the need to perform similar, grouped, repetitive operations that typically get performed all together. That is not the problem that you are trying to solve.
If your main gripe is that you don't like having three lines of code, why not just use a helper whose name indicates what you're trying to do?
TModel MapToModel<TModel, TDto>(TDto dto, TModel model)
where TModel : IConvertableModel<TDto>
{
model.SetFromDto(dto);
return model;
}
// usage:
var dto = _dtoRepository.GetFirstDto();
return MapToModel(dto, new DisplayEditModel());
... or even:
TModel CreateModel<TModel, TDto>(TDto dto)
where TModel : IConvertableModel<TDto>, new()
{
var model = new TModel();
return MapToModel(dto, model);
}
// usage:
var dto = _dtoRepository.GetFirstDto();
return CreateModel<DisplayEditModel>(dto);
This is simple, readable, and feasible, whereas the approach you're suggesting would break the IConvertableModel<Display> interface:
public interface IConvertableModel<TDto>
{
public TDto ToDto();
public ??? SetFromDto(TDto dto);
}
What would SetFromDto return? You would have to define another generic type on IConvertableModel.
public interface IConvertableModel<TDto, TModel> {
public TDto ToDto();
public TModel SetFromDto(TDto dto);
}
But this wouldn't really indicate that the SetFromDto method is necessarily returning itself, because it allows for a class that is not a TModel to implement IConvertableModel to convert between two other types.
Now, you could go out of your way to push the generics even farther:
public interface IConvertableModel<TDto, TModel>
where TModel : IConvertableModel<TDto, TModel>
{...}
But this still allows for some fudging, and the interface cannot guarantee that you are really returning "this" object. All in all, I'm not a big fan of that approach.
Rather than having DisplayEditModel have a get/set method for a Display object to get/set the values, just use a property that doesn't actually have a separate backing store:
public Display Display
{
get
{
return new Display
{
Description = Description,
ObjectId = ObjectId,
};
}
set
{
Description = value.Description;
ObjectId = value.ObjectId;
}
}
Now you can use an object initializer with this property when creating a model:
return new DisplayEditModel() { Display = dto };
This is a very javascript way of approaching this problem, though it has it's benefits. In the context of C#, it is a little bit strange though libraries such as LINQ do this to allow chaining together function calls.
My only worry about this, is that this has to be a class that does this consistently. Implementing a chaining function return pattern is not really a convenience as much as it is a design choice. The rule to follow in this case, would be to return this every time you mutate the object.
Chaining also may not be worth it performance wise. Something that can be done by wrapping all those operations into a single function is much faster. For instance:
MyVector.setX(1).SetY(1).SetZ(1).SetW(0)
is a lot slower than simply
MyVector.set(1, 1, 1, 0)
because now you are now doing excessive stack operations to do something fairly simple. It only becomes worth it on very large operations that take up the bulk of the computing time and make sense to chain together. For this reason, LINQ allows you to chain things together.
I wouldn't say that it necessary "harms" or is dangerous. We are in the world of a managed language, so we don't have direct access to that memory location (unlike C/C++). So I would just call it a design choice which can be fairly powerful in some cases and not so much in others.
As noted, chainable methods work fine but are not as common in C# as in some other languages. If the extra lines of code only happen in one place, I'd just leave it alone. If it's really bugging you or you do it a lot, then consider implementing a special constructor for it:
public void DisplayEditModel(Display dto)
{
this.SetFrom(dto);
}
or a static factory method:
public static DisplayEditModel CreateFrom(Display dto)
{
var model = new DisplayEditModel();
model.SetFrom(dto);
return model;
}
Either option has a clear intent, lets you create and return the object in a single line, and is idiomatic. It does require a few extra lines of code in DisplayEditModel, but I doubt it will be a serious problem.

Possible ways to return a subset of data from Repository<T>?

Let's say I need to display a list of customers, but only want to display the Name and somehow associate the key to the name within a list control.
It would probably be costly to retrieve the entire list of customers and all it's properties. In this scenario, would it be better to create another class with the properties that are required (in this case Id and Name)?
A basic implementation could look like this:
public class Customer {
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
.....
}
public class CustomerListView {
public int Id { get; set; }
public string Name { get; set; }
}
public interface IRepository<T> {
public T Find(int id);
public IEnumerable<T> FindAll();
....
}
public class Repository<T>: IRepository<T> {
....
}
public class CustomerRepository: Repository<Customer> {
public IEnumerable<CustomerListView> FindAllListView();
}
Would this approach be appropriate? What other options would there be?
In order to achieve such goals, I create a simple 'View' class, for example CustomerView, which just contains the properties that are needed to display an overview.
My Repository then has a method which returns a collection of these CustomerView objects.
I mostly use NHibernate in my projects. Nhibernate allows you to use 'projections'.
So, what I do in my repository is this:
(note that the code below is just some pseudo-code; it won't compile).
public IList<CustomerView> GetAllCustomers()
{
ICriteria crit = _session.CreateCriteria (typeof(Customer));
crit.AddProjection ( ... );
crit.SetResultTransformer (new EntityToBeanTransformer(typeof(CustomerView));
return crit.ToList();
}
In fact, it comes down to this: I tell my O/R mapper that it should query Customers, but that it should return entities of type 'CustomerView'.
In the defintion of the projection, I also define which properties of the Customer class map to which properties of the CustomerView class.
Then, the O/R mapper is smart enough to generate a very simple query, which only retrieves those fields that are required to populate the CustomerView class.
For instance, the query that is executed can be as simple as:
SELECT customerid, customername FROM tblCustomer
If you use IQueryable as your return instead of IEnumerable than there is no cost of doing:
CustomerRepository().GetAll().Find(1) because AsQueryable doesn't actually execute until you request data. That means LINQ can optimize it out to a:
SELECT .... FROM .... WHERE ID = 1 instead of
GET EVERYTHING. FIND WHERE THE ID = 1
See this post for an explanation:
Why use AsQueryable() instead of List()?
Using this approach you could create an anonymous class and futher narrow down the data going over the wire to just what you want. That way the query generated by LINQ is optimized to the fullest.
If you have to retrieve the list form a Database then your proposal makes some sense but I would look into a Linq and anonymous type solution.
If the list of Customers already exists in memory then there there are no savings.
You could combine the techniques used by Nissan and Frederik (anonymous types and NHibernate) by using Linq-to-NHibernate.
Item #31 in Bill Wagner's More Effective C# says "limit type scope by using anonymous types", and I agree. BTW, I recommend the whole book.

Categories