PetaPoco Query View Always Returns NULLS - c#

I have the below view in SQL Server represented using PetaPoco in my C# application:
/// <summary> Rep Level Keys. </summary>
[TableName("vXPATRepLevelKeys")]
[ExplicitColumns]
public partial class vXPATRepLevelKeys : dbo.Record<vXPATRepLevelKeys>
{
/// <summary> Gets or sets the RepLevelKey. </summary>
public string RepLevelKey { get; set; }
}
However, when I attempt to select from the view using:
var result = _database.Fetch<xPAT.vXPATRepLevelKeys>("SELECT * FROM vXPATRepLevelKeys").OrderBy(x => x.RepLevelKey);
var asStrings = result.Select(x => x.RepLevelKey).ToList();
I just get a list of NULL values. asStrings has 33 items in the list, all being NULL. However, when I run the above view myself, I get 33 non-null results.
I'm new to PetaPoco (tbh, I'm not even sure if it is a PetaPoco related issue) and have inherited this application, which I'm attempting to add this new view to so any help is greatly appreciated.

If you use the [ExplicitColumns] attribute, you must use the [Column] attribute on each property
[Column]
public string RepLevelKey { get; set; }

Related

Swagger UI Response Example Asp.Net Core Web Api

I'm using Swagger.AspNetCore to document my api. So far i was happy to use xml comments to generate response model examples until i reach the point when i've got to document embeded object. So i have simple model:
public class SummaryResult
{
/// <summary>Total Cost.</summary>
/// <value>Total Cost.</value>
/// <example>6433.2</example>
public double TotalCost { get; set; }
/// <summary>Owner.</summary>
public Owner Owner { get; set; }
}
public class Owner
{
/// <summary>Owner Name.</summary>
/// <value>Owner Name.</value>
/// <example>Michael</example>
public string Name { get; set; }
}
And Swagger UI document it only for TotalCost, Owner property just skipped whatever i do. Does anyone have a clue why this can happen? And how to fix it.
I know how to deal with List - just put on top xml comment like <list></list> but it's not my case.
Thank you
I just tested this and it shows fine on my end:
http://swagger-net-test.azurewebsites.net/swagger/ui/index#/ActionFilter/ActionFilter_Get
Here is how that looks like on the model tab:
As you can see in the image it does show the summary and the example value.
Here is the code:
https://github.com/heldersepu/Swagger-Net-Test/blob/master/Swagger_Test/Controllers/ActionFilterController.cs#L29
Educated guess there could be something else removing those elements.

Null fields on a partial update mutation on GraphQL .NET

At work, we're using EFCore on our data layer and graphql-dotnet to manage APIs requests, I'm having a problem updating some of our big objects using GraphQL mutations. When the user sends a partial update on the model, we would like to update on our database only the fields that actually were changed by the mutation. The problem we're having is that as we directly map the input to the entity, wheather some field was purposefully passed as null, or the field was not specified on the mutation at all, we get the property value as null. This way we can't send the changes to the database otherwise we would incorrectly update a bunch of fields to null.
So, we need a way to identify which fields are sent in a mutation and only update those. In JS this is achieved by checking if the property value is undefined, if the value is null we know that it was passed as null on purpose.
Some workarounds we've been thinking were using reflection on a Dictionary to update only the specified fields. But we would need to spread reflection to every single mutation. Another solution was to have a isChanged property to every nullable property on our model and change ir on the refered property setter, but... cmon...
I'm providing some code as example of this situation bellow:
Human class:
public class Human
{
public Id { get; set; }
public string Name { get; set; }
public string HomePlanet { get; set; }
}
GraphQL Type:
public class HumanType : ObjectGraphType<Human>
{
public HumanType()
{
Name = "Human";
Field(h => h.Id).Description("The id of the human.");
Field(h => h.Name, nullable: true).Description("The name of the human.");
Field(h => h.HomePlanet, nullable: true).Description("The home planet of the human.");
}
}
Input Type:
public class HumanInputType : InputObjectGraphType
{
public HumanInputType()
{
Name = "HumanInput";
Field<NonNullGraphType<StringGraphType>>("name");
//The problematic field
Field<StringGraphType>("homePlanet");
}
}
Human Mutation:
/// Example JSON request for an update mutation without HomePlanet
/// {
/// "query": "mutation ($human:HumanInput!){ createHuman(human: $human) { id name } }",
/// "variables": {
/// "human": {
/// "name": "Boba Fett"
/// }
/// }
/// }
///
public class StarWarsMutation : ObjectGraphType<object>
{
public StarWarsMutation(StarWarsRepository data)
{
Name = "Mutation";
Field<HumanType>(
"createOrUpdateHuman",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<HumanInputType>> {Name = "human"}
),
resolve: context =>
{
//After conversion human.HomePlanet is null. But it was not informed, we should keep what is on the database at the moment
var human = context.GetArgument<Human>("human");
//On EFCore the Update method is equivalent to an InsertOrUpdate method
return data.Update(human);
});
}
}
You could use JsonConvert.PopulateObject from the Newtonsoft Json library. On the mutation resolver instead of using GetArgument with my type, I'm using GetArgument<dynamic> and serializing it using JsonConvert.SerializeObject then by calling JsonConvert.PopulateObject I'm able to update only the fields that were informed.
public StarWarsMutation(StarWarsRepository data)
{
Name = "Mutation";
Field<HumanType>(
"createOrUpdateHuman",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<HumanInputType>> {Name = "human"}
),
resolve: context =>
{
//After conversion human.HomePlanet is null. But it was not informed, we should keep what is on the database at the moment
var human = context.GetArgument<dynamic>("human");
var humanDb = data.GetHuman(human["id"]);
var json = JsonConvert.SerializeObject(human);
JsonConvert.PopulateObject(json, humanDb);
//On EFCore the Update method is equivalent to an InsertOrUpdate method
return data.Update(humanDb);
});
}

Fitbit get distance data in miles not kilometers

I have a sample project that gets data from Fitbit but the information comes in metric system not imperial system. Here is the code that pulls a list of Dates and Strings pair using TimeSeriesDataList class, but in kilometers not miles. How can I modify this code to get the data in miles instead of kilometers? Any help is greatly appreciated.
public class TimeSeriesDataList
{
public List<Data> DataList { get; set; }
public class Data
{
public DateTime DateTime { get; set; }
public string Value { get; set; }
}
}
public class FitbitClient : IFitbitClient
{
/// <summary>
/// Get TimeSeries data for another user accessible with this user's credentials
/// </summary>
/// <param name="timeSeriesResourceType"></param>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <param name="userId"></param>
/// <returns></returns>
private TimeSeriesDataList GetTimeSeries(TimeSeriesResourceType timeSeriesResourceType, DateTime baseDate, string endDateOrPeriod, string userId)
{
string userSignifier = "-"; //used for current user
if (!string.IsNullOrWhiteSpace(userId))
userSignifier = userId;
// Here is where I believe I need to make a change, somehow, so that
// data that comes in when this is string is requested, comes in metric units
string requestUrl = string.Format("/1/user/{0}{1}/date/{2}/{3}.xml", userSignifier, StringEnum.GetStringValue(timeSeriesResourceType), baseDate.ToString("yyyy-MM-dd"), endDateOrPeriod);
RestRequest request = new RestRequest(requestUrl);
request.OnBeforeDeserialization = resp => {
XDocument doc = XDocument.Parse(resp.Content);
//IEnumerable<XElement> links = doc.Descendants("result");
var rootElement = doc.Descendants("result").FirstOrDefault().Descendants().FirstOrDefault();
if (rootElement != null && !string.IsNullOrWhiteSpace(rootElement.Name.LocalName))
request.RootElement = rootElement.Name.LocalName;
};
var response = restClient.Execute<TimeSeriesDataList>(request);
HandleResponse(response);
return response.Data;
}
}
EDIT I am looking to get the data already converted by adding something along the lines of "Accept-Language" to the header, but I do not know how to utilize that concept. Using conversion crossed my mind but at this time I would like to see if there is an easier way by adding a simple header rather than creating a conversion class for every scenario, class holding the data, for each distinct region, etc.
I did a quick search and am assuming that RestRequest is the class from the RestSharp library. If so, according to their web site (http://restsharp.org) you would do something like:
request.AddHeader("Accept-Language", "...");
Not sure what the correct value should be, you'll need to figure that out from FitBit's API documentation.
Whatever value this code provides, you can simply divide it by 1.60934 to get the same distance in miles. Hope that helps you solve it.
double kilometers2 = 321.9;
double miles2 = ConvertDistance.ConvertKilometersToMiles

Implementing a feature to track if the user is repeating a search

I have a view model that represents all the fields available for searching. I'd like to add some logic that would be able to identify if the search values are all the same and determine whether to hit the DB again for their query.
I think I would have to do something like..
after user submits form save form values to some
temporary field.
upon second submission compare temp value to form values collection.
if values are equal set property in view
model IsSameSearch = true
I'd like to use the Post Redirect Get Pattern too. So that My search View doesn't do anything except post the form values to another action that processes and filters the data, which is then "Getted" using Ajax.
The SearchViewModel contains many many search parameters. Here is an abbreviated version.
public bool UseAdvancedSearch { get; set; }
public bool isSameSearch { get; set; }
/// <summary>
/// Gets or sets the page.
/// </summary>
[HiddenInput]
[ScaffoldColumn(false)]
public int Page { get; set; }
[HiddenInput]
[ScaffoldColumn(false)]
public string SortOption { get; set; }
/// <summary>
/// Gets or sets the address keywords.
/// </summary>
[Display(Name="Address")]
public string AddressKeywords { get; set; }
/// <summary>
/// Gets or sets the census.
/// </summary>
public string Census { get; set; }
/// <summary>
/// Gets or sets the lot block sub.
/// </summary>
public string LotBlockSub { get; set; }
/// <summary>
/// Gets or sets the owner keywords.
/// </summary>
[Display(Name="Owner")]
public string OwnerKeywords { get; set; }
/// <summary>
/// Gets or sets the section township range.
/// </summary>
public string SectionTownshipRange { get; set; }
/// <summary>
/// Gets or sets the strap.
/// </summary>
///
[Display(Name="Account Number/Parcel ID")]
public string Strap { get; set; }
/// <summary>
/// Gets or sets the subdivision.
/// </summary>
public string Subdivision { get; set; }
/// <summary>
/// Gets or sets the use code.
/// </summary>
[Display(Name = "Use Code")]
public string UseCode { get; set; }
/// <summary>
/// Gets or sets the zip code.
/// </summary>
[Display(Name="Zip Code")]
public string ZipCode { get; set; }
If you are getting data from Entity Framework you could cache the data at EF level. Look at the package entity framework extended https://github.com/loresoft/EntityFramework.Extended. It is as simple as adding method .FromCache () to the query you use to retrieve and filter the data and it will cache the query result. Make sure you load all the data required using includes etc.
You wouldn't have to worry about same search in model as the caching provider would look at filter settings and determine that it was different. Alternatively cache the data before filtering and then filter the cached results. This is more appropriate if you have lots of filter parameters with significant variance as you will only have to cache 1 large result rather than thousands of smaller results.
You can get more advanced and specify cache period e.g. Cache for 10 minutes
What you are describing is called caching.
One way to accomplish that in your scenario would be to implement GetHashCode() in a way that it would take into account all your fields/properties to compute a unique value. That way you can use your Hash as the key entry in your cache, and store the results with that key.
For that actual caching you could just use the MemoryCache class provided by the .Net Framework if you are not deploying to a web farm.
Also, if you are familiar with IoC and DI (such as using Unity), things like this can be implemented as an Interceptor, and only requiring you to add an attribute to the method you'd like to cache. That way you implement caching only once as a cross-cutting concern and not fill up your application code with things like this.

NEST C# - elasticsearch - ecommerce filter combination

I am trying to implement elasticsearch into my webshop but having some troubles on using filters. The filtering is done dynamically.
Example:
I start with showing all the products that are indexed. So no filter is applied. Visitors can choose their own filters like: color, size, brand, type, category, ....
But I don't now how to build the search result with elasticsearch and NEST.
This is my solution without filtering:
var query = ElasticClient.Search<Product>(s => s
.From(from)
.Size(size)
);
I also have another question on indexing a collection<> or list<>. I had to use JsonIgnore on those collections. Could I index those as well?
This is my class:
/// <summary>
/// Represents a product
/// </summary>
public partial class Product {
private ICollection<ProductCategory> _productCategories;
private ICollection<ProductManufacturer> _productManufacturers;
private ICollection<ProductPicture> _productPictures;
/// <summary>
/// Gets or sets the name
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// Gets or sets the short description
/// </summary>
public virtual string ShortDescription { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity is published
/// </summary>
public virtual bool Published { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public virtual bool Deleted { get; set; }
/// <summary>
/// Gets or sets the date and time of product creation
/// </summary>
public virtual DateTime CreatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the date and time of product update
/// </summary>
public virtual DateTime UpdatedOnUtc { get; set; }
/// <summary>
/// Gets or sets the collection of ProductCategory
/// </summary>
[JsonIgnore] /* added - wesley */
public virtual ICollection<ProductCategory> ProductCategories
{
get { return _productCategories ?? (_productCategories = new List<ProductCategory>()); }
protected set { _productCategories = value; }
}
/// <summary>
/// Gets or sets the collection of ProductManufacturer
/// </summary>
[JsonIgnore] /* added - wesley */
public virtual ICollection<ProductManufacturer> ProductManufacturers
{
get { return _productManufacturers ?? (_productManufacturers = new List<ProductManufacturer>()); }
protected set { _productManufacturers = value; }
}
/// <summary>
/// Gets or sets the collection of ProductPicture
/// </summary>
[JsonIgnore] /* added - wesley */
public virtual ICollection<ProductPicture> ProductPictures
{
get { return _productPictures ?? (_productPictures = new List<ProductPicture>()); }
protected set { _productPictures = value; }
}
}
Is there someone who can help me?
Be sure to read the whole documentation on writing queries here: http://nest.azurewebsites.net/nest/writing-queries.html
What follows is a pasted excerpt from there.
Conditionless queries
Writing complex boolean queries is one thing but more often then not you'll want to make decisions on how to query based on user input.
public class UserInput
{
public string Name { get; set; }
public string FirstName { get; set; }
public int? LOC { get; set; }
}
and then
.Query(q=> {
QueryDescriptor<ElasticSearch> query = null;
if (!string.IsNullOrEmpty(userInput.Name))
query &= q.Term(p=>p.Name, userInput.Name);
if (!string.IsNullOrEmpty(userInput.FirstName))
query &= q
.Term("followers.firstName", userInput.FirstName);
if (userInput.LOC.HasValue)
query &= q.Range(r=>r.OnField(p=>p.Loc).From(userInput.Loc.Value))
return query;
})
This again turns tedious and verbose rather quickly too. Therefor nest allows you to write the previous query as:
.Query(q=>
q.Term(p=>p.Name, userInput.Name);
&& q.Term("followers.firstName", userInput.FirstName)
&& q.Range(r=>r.OnField(p=>p.Loc).From(userInput.Loc))
)
If any of the queries would result in an empty query they won't be sent to elasticsearch.
So if all the terms are null (or empty string) on userInput except userInput.Loc it wouldn't even wrap the range query in a boolean query but just issue a plain range query.
If all of them empty it will result in a match_all query.
This conditionless behavior is turned on by default but can be turned of like so:
var result = client.Search<ElasticSearchProject>(s=>s
.From(0)
.Size(10)
.Strict() //disable conditionlessqueries by default
///EXAMPLE HERE
);
However queries themselves can opt back in or out.
.Query(q=>
q.Strict().Term(p=>p.Name, userInput.Name);
&& q.Term("followers.firstName", userInput.FirstName)
&& q.Strict(false).Range(r=>r.OnField(p=>p.Loc).From(userInput.Loc))
)
In this example if userInput.Name is null or empty it will result in a DslException. The range query will use conditionless logic no matter if the SearchDescriptor uses .Strict() or not.
Also good to note is that conditionless query logic propagates:
q.Strict().Term(p=>p.Name, userInput.Name);
&& q.Term("followers.firstName", userInput.FirstName)
&& q.Filtered(fq => fq
.Query(qff =>
qff.Terms(p => p.Country, userInput.Countries)
&& qff.Terms(p => p.Loc, userInput.Loc)
)
)
If both userInput.Countries and userInput.Loc are null or empty the entire filtered query will be not be issued.

Categories

Resources