Generic C# method for RavenDB (5.3) to return property subset for any document type - ravendb

I'm trying to create a generic C# method that can return just the Id & Description (string) properties for a particular document type in a generic BasicObject class. (Most of my document types have Id & Description properties).
The method would accept the document type and (presumably) an expression that would be passed as a parameter to the .Select part of the query definition. The expression would convert the document type to a BasicObject (Id & Description properties).
I've tried the method below but RavenDB doesn't understand the expression. Is it possible to do what I need or do I have to implement the method for each document type.
public Task<List<T>> GetAllDocs(Expression<Func<T, BasicObject> convertExpression)
{
var query = _session.Query<T>
.Select(doc => convertExpression(doc));
var results = await query.ToListAsync();
return results;
}

Related

SQL-Query returns 'sql-select' string instead of record-set

I'm querying a SQL table via an API and I expect the API to return a <IQueryable> collection of 'Outfit' objects however, the response object is actually just a string containing the sql-select statement.
Questions:
Why is the response object returning the SQL-select statement as a string?
Should the IQueryable<> contain a collection of 'Outfit' objecy-types? And should the object-type 'Outfit' be a C# class OR can I use a generic type like 'object' to hold each 'outfit' in the collection?
//Endpoint setup within the APIcontroller.cs file
[Route("api/getSummerOutfits")]
[HttpGet]
[Authorize]
public string getSummerOutfits()
{
IQueryable<Outfit> outfits = _dbContext.Outfits.Where(outfit => outfit.Type == 'Summer');
return outfits;
}
//Setup for the service within the api.service.ts file
getSummerOutfits(): Observable<Object>
{
return this.httpClient.get('/api/getSummerOutfits').pipe();
}
//A snippet of the response-string when the API is called within Postman
"SELECT \r\n ....... WHERE Outfit.Type = 'Summer'"
I have tried setting the IQueryable<> to contain objects of-type 'outfit' however the response continues to be a string containing the sql-select statement.
The query is declared but never executed.
IQueryable<T> (Remarks section)
Enumeration causes the expression tree associated with an IQueryable object to be executed.
Queries that do not return enumerable results are executed when the Execute method is called.
You have to materialize the query with .ToList() or .AsEnumerable().
public List<Outfit> getSummerOutfits()
{
List<Outfit> outfits = _dbContext.Outfits
.Where(outfit => outfit.Type == 'Summer')
.ToList();
return outfits;
}
While I suggest removing.pipe() as you didn't perform any operation in the response. And return the value of Observable<any[]> or Observable<Outfit[]> if you have write Outfit class/interface.
getSummerOutfits(): Observable<any[]>
{
return this.httpClient.get<any[]>('/api/getSummerOutfits');
}
I'm surprised that even worked. Essentially it passed back an IQueryable<Outfit>.ToString() result.
To return a collection of Outfits Yong Shun's answer covers that using a ToList() and having the return type being an IEnumerable<Outfit>/ ICollection<Outfit>.
As a general rule though I don't recommend passing entities back to views or API, especially for asynchronous AJAX calls as this will typically send far more information than the consumer needs, and potentially opens you up to serialization "traps" with lazy loading.
Instead, define a view model or a DTO, which is a serializable POCO C# object containing just the fields your consumer needs. Then your method becomes:
public IEnumerable<OutfitDto> getSummerOutfits()
{
var outfits = _dbContext.Outfits
.Where(outfit => outfit.Type == 'Summer')
.Select(outfit => new OutfitDto
{
// copy values across here.
}).ToList();
return outfits;
}
This avoids the possibility that a serializer attempts to lazy load navigation properties in Outfit. It reduces the size of the payload by just including the fields that you need, and removes any need to eager-load entire related entities if there are details you want from those. (just reference the related entity properties, EF will build the suitable query) It also avoids confusion especially if you go to pass an outfit DTO back to the server rather than attempting to send what you think is an Entity which is actually nothing more than a serialized JSON object or set of parameters type-cast into an Entity class.

How to change the format of an attribute in a CActiveRecord returned by a findAll method?

I have an attribute in my model that is stored in binary format inside database.
In case the attribute is a geometric( polygon ) object.
This object can be casted to several string representations.
So how can I attach an event after a find execution that allows me to change the attribute on returned set only?
My first guess was to use the onAfterFind event but it is not calling the handler with the created element as documentation suggests. My first attempt was the following in the controller.
// an activeRecord class
GeoTableBinaryData extends CActiveRecord {
... // normal active record with a table which has a binary attribute called geom
}
$model = GeoTableBinaryData::model();
$model->onAfterFind->add(
function( CEvent $evt ){
// get the finded object to update the geom attribute on the fly here want
// a text representation in other case would transform it to XML or JSON
}
);
foreach ( $model->findAll() as $geoInfo )
{
... // output serialized geometry
}
The correct way of doing this, is that in your model have a afterFind method like:
protected function afterFind()
{
$this->someAttribute = $this->methodToChangeTheAttribute($this->someAttribute);
return parent::afterFind();
}
and that's all, when you will use AR's methods, every found model will pass through afterFind() and alter the someAttribute as you want.
You can also write getters for your different formats:
public function getGeoAsString()
{
// Create the string from your DB value. For example:
return implode(',', json_decode($this->geom));
}
Then you can use the geoAsString like a regular (read-only) attribute. You can also add a setter method, if you want to make it writeable.

One method to read parameters, properties and return types at runtime using C#

With continutation to my earlier thread Using reflection read properties of an object containing array of another object. I am hoping to make this wonderful method from EvgK a generic method that can be used in multiple places in my code base.
public static void GetMyProperties(object obj)
{
List<MyPropertyInfo> oMyProp = new List<MyPropertyInfo>();
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
if (!Helper.IsCustomType(pinfo.PropertyType))
{
//add properties - name, value, type to the list
}
else
{
var getMethod = pinfo.GetGetMethod();
if (getMethod.ReturnType.IsArray)
{
var arrayObject = getMethod.Invoke(obj, null);
foreach (object element in (Array)arrayObject)
{
foreach (PropertyInfo arrayObjPinfo in element.GetType().GetProperties())
{
//add properties - name, value, type to the list
}
}
}
else
{
List<MyPropertyInfo> oTempMyProp = GetMyProperties(prop.GetValue(obj, null));
oMyProp.AddRange(oTempMyProp);
}
}
}
}
Again, I am trying to read a method passed by the user. I list the parameters, their properties and values. Once user provides the input values, I call the method dynamically to get the result object. The result is passed to GetMyProperties() method and the method list all the properties (to n level) - name, value and type.
Currently, I have two methods (definations below):
public List<MyPropertyInfo> GetMyProperties(Type type);
public List<MyPropertyInfo> GetMyProperties(object obj);
I use the first one to show the list of all the parameters of the selected method along with it's properties - name, value and type.
MethodInfo members = type.GetMethod(this.MethodName);
ParameterInfo[] parameters = members.GetParameters();
List<MyPropertyInfo> oMyProp = new List<MyPropertyInfo>();
foreach (var parameter in parameters)
{
oMyProp = GetMyProperties(parameter.ParameterType);
}
..creating the list of my properties so that user can input the params. I pass ParameterType and GetProperties method checks if it is custom type or not. If custom type then it calls itself with the type recursively to build a list that I bind to a grid for input.
The second method GetMyProperties(object obj) is used to list the return object. Since I don't know the return type of the selected method at compile time so using object type. I want to know if I can modify the second method somehow to use it for reading the parameters, properties and return types? Instead of having separate methods? Trying to reuse the code.
I'm not sure I understand you correctly, but if you want to combine two methods in one, you can pass object in both cases, but check if object is Type or not and provide different logic for that cases:
public static void GetMyProperties(object obj)
{
if (obj is Type)
{
Type type = obj as Type;
... here is the first method logic ...
}
else
{
... here is the second method logic ...
}
}

How to set the value of a shared parameter with type binding in Autodesk Revit Architecture 2010?

I have a shared parameter UValue bound to the Wall type with TypeBinding in Autodesk Revit Architecture 2010.
I can easily access the parameter with:
Definition d = DefinitionFile.Groups.get_Item("groupname").Definitions.get_Item("UValue");
Parameter parameter = self.get_Parameter("UValue");
The value of this parameter can be looked at with
var u = parameter.AsDouble();
But when I do
parameter.Set(0.8);
I get an Error:
InvalidOperationException: Operation is not valid due to the current state of the object.
On inspection, the parameters ReadOnly property is set to false.
Ok, I have found the problem:
When using TypeBinding, the parameter is not in the Wall object itself, but in its WallType property. If you are doing this in a polymorphic way (not just walls, but also floors, roofs etc.), then you can use the Element.ObjectType property.
The code in the OP should thus have been:
Definition d = DefinitionFile.Groups.get_Item("groupname").Definitions.get_Item("UValue");
Parameter parameter = self.ObjectType.get_Parameter("UValue");
This is being called from an extension method, a rather neat technique for adding parameters to Revit objects.
Setting the parameter can thus be done like this:
public static void SetUValue(this Wall self, double uvalue)
{
Parameter parameter = self.ObjectType.get_Parameter("UValue");
if (parameter != null)
{
parameter.Set(uvalue);
}
else
{
throw new InvalidOperationException(
"Wall does not contain the parameter 'UValue'");
}
}

Dynamic Table Names in Linq to SQL

Hi all I have a horrid database I gotta work with and linq to sql is the option im taking to retrieve data from. anywho im trying to reuse a function by throwing in a different table name based on a user selection and there is no way to my knowledge to modify the TEntity or Table<> in a DataContext Query.
This is my current code.
public void GetRecordsByTableName(string table_name){
string sql = "Select * from " + table_name;
var records = dataContext.ExecuteQuery</*Suppossed Table Name*/>(sql);
ViewData["recordsByTableName"] = records.ToList();
}
I want to populate my ViewData with Enumerable records.
You can call the ExecuteQuery method on the DataContext instance. You will want to call the overload that takes a Type instance, outlined here:
http://msdn.microsoft.com/en-us/library/bb534292.aspx
Assuming that you have a type that is attributed correctly for the table, passing that Type instance for that type and the SQL will give you what you want.
As casperOne already answered, you can use ExecuteQuery method first overload (the one that asks for a Type parameter). Since i had a similar issue and you asked an example, here is one:
public IEnumerable<YourType> RetrieveData(string tableName, string name)
{
string sql = string.Format("Select * FROM {0} where Name = '{1}'", tableName, name);
var result = YourDataContext.ExecuteQuery(typeof(YourType), sql);
return result;
}
Pay attention to YourType since you will have to define a type that has a constructor (it can't be abstract or interface). I'd suggest you create a custom type that has exactly the same attributes that your SQL Table. If you do that, the ExecuteQuery method will automatically 'inject' the values from your table to your custom type. Like that:
//This is a hypothetical table mapped from LINQ DBML
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ClientData")]
public partial class ClientData : INotifyPropertyChanging, INotifyPropertyChanged
{
private int _ID;
private string _NAME;
private string _AGE;
}
//This would be your custom type that emulates your ClientData table
public class ClientDataCustomType
{
private int _ID;
private string _NAME;
private string _AGE;
}
So, on the former example, the ExecuteQuery method would be:
var result = YourDataContext.ExecuteQuery(typeof(ClientDataCustomType), sql);