None of the similarly worded questions on SO seem to match, and googling pretty much points to SO for this, so let's try this:
I have a JournalEntry entity class that looks like this:
public partial class JournalEntry
{
public virtual Guid JournalEntryId { get; set; }
public virtual Account Account { get; set; }
public virtual decimal DebitAmount { get; set; }
public virtual decimal CreditAmount { get; set; }
[NotNull]
public virtual DateTime EffectiveDate { get; set; }
[NotNull]
public virtual DateTime PostingDate { get; set; }
public virtual UserProfile PostedBy { get; set; }
[FullTextIndexed]
public virtual string Notes { get; set; }
public virtual Amortization Amortization { get; set; }
public virtual ExpenseCategories ExpenseCategory { get; set; }
[Index]
public virtual bool IsClosed { get; set; }
}
I also have a simple class for holding transaction summaries like so:
public class JournalEntrySummary
{
public decimal Credits { get; set; }
public decimal Debits { get; set; }
}
What I would like to do is write a Criteria query that will return the sums of both the Credits property and the Debits property. IOW, I would like something vaguely shaped like this SQL query:
select
sum(creditamount) as Credits,
sum(debitamount) as Debits
from
journalentries
where
...
... and have that populate my JournalEntrySummary object. I've seen lots of examples of how to do one column, and even some examples of adding the two columns together, but no examples of collecting the two distinct summaries and dumping them into a non-domain object.
Is this possible? How would I do it?
Take a look at criteria queries documentation http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection, there are some examples that will answer you question.
For your example you should try this
// using NHibernate.Criterion;
// using NHibernate.Transform;
session.CreateCriteria<JournalEntry>()
.SetProjection(
Projections.Sum<JournalEntry>(x => x.DebitAmount).As("Debits"),
Projections.Sum<JournalEntry>(x => x.CreditAmount).As("Credits"),
// you can use other aggregates
// Projections.RowCount(),
// Projections.Max<JournalEntry>(x => x.EffectiveDate)
)
.SetResultTransformer(Transformers.AliasToBean<JournalEntrySummary>())
.UniqueResult<JournalEntrySummary>();
Related
I was looking to find a simple way to map a class property to a table column and I found Dapper fluent map which I thought was going to be a great alternative to the considerable boilerplate code that one would need to write simply to map a property to a column. But it does not seem to work.
FluentMapper.Initialize(c =>
{
c.AddMap(new MarginSummaryMap());
});
[Serializable]
[Table("PbCash")]
public class MarginSummary : Entity
{
public long RunId { get; set; }
public DateTime? BusinessDate { get; set; }
[Write(false)]
public DateTime ProcessDate { get; set; }
public string Broker { get; set; }
public string BrokerAccountId { get; set; }
public string Account { get; set; }
public string Folio { get; set; }
public decimal? ActualExcessOrDeficit { get; set; }
[Write(false)]
public decimal? ProjectedExcessOrDeficit { get; set; }
public string Comment { get; set; }
}
public class MarginSummaryMap : EntityMap<MarginSummary>
{
public MarginSummaryMap()
{
Map(c => c.ActualExcessOrDeficit).ToColumn("ExcessOrDeficit");
}
}
Then when I am trying to save data I get an exception that the column ActualExcessOrDeficit does not exist in the table. Well it does not and the mapping is supposed to convert to the actual column ExcessOrDeficit.
Looks like this is a bug in Dapper.FluentMap since the problem goes way if I change type from decimal? to decimal.
Did anyone have this working - I would love to know how to fix this.
EDIT: I originally worded this question very poorly, stating the problem was with JSON serialization. The problem actually happens when I'm converting from my base classes to my returned models using my custom mappings. I apologize for the confusion. :(
I'm using .NET Core 1.1.0, EF Core 1.1.0. I'm querying an interest and want to get its category from my DB. EF is querying the DB properly, no problems there. The issue is that the returned category has a collection with one interest, which has one parent category, which has a collection with one interest, etc. When I attempt to convert this from the base class to my return model, I'm getting a stack overflow because it's attempting to convert the infinite loop of objects. The only way I can get around this is to set that collection to null before I serialize the category.
Interest/category is an example, but this is happening with ALL of the entities I query. Some of them get very messy with the loops to set the relevant properties to null, such as posts/comments.
What is the best way to address this? Right now I'm using custom mappings that I wrote to convert between base classes and the returned models, but I'm open to using any other tools that may be helpful. (I know my custom mappings are the reason for the stack overflow, but surely there must be a more graceful way of handling this than setting everything to null before projecting from base class to model.)
Classes:
public class InterestCategory
{
public long Id { get; set; }
public string Name { get; set; }
public ICollection<Interest> Interests { get; set; }
}
public class Interest
{
public long Id { get; set; }
public string Name { get; set; }
public long InterestCategoryId { get; set; }
public InterestCategory InterestCategory { get; set; }
}
Models:
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public long? InterestCategoryId { get; set; }
}
Mapping functions:
public static InterestCategoryModel ToModel(this InterestCategory category)
{
var m = new InterestCategoryModel
{
Name = category.Name,
Description = category.Description
};
if (category.Interests != null)
m.Interests = category.Interests.Select(i => i.ToModel()).ToList();
return m;
}
public static InterestModel ToModel(this Interest interest)
{
var m = new InterestModel
{
Name = interest.Name,
Description = interest.Description
};
if (interest.InterestCategory != null)
m.InterestCategory = interest.InterestCategory.ToModel();
return m;
}
This is returned by the query. (Sorry, needed to censor some things.)
This is not .NET Core related! JSON.NET is doing the serialization.
To disable it globally, just add this during configuration in Startup
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}));
edit:
Is it an option to remove the circular references form the model and have 2 distinct pair of models, depending on whether you want to show categories or interests?
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
public List<InterestModel> Interests { get; set; }
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
public class InterestModel
{
public long Id { get; set; }
public string Name { get; set; }
public InterestCategoryModel InterestCategory { get; set; }
public class InterestCategoryModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Note that each of the models has a nested class for it's child objects, but they have their back references removed, so there would be no infinite reference during deserialization?
How to: Do nested lists in sqlite-net-extensions
Answer Found: Keeping the question as an example of how to do it.
The problem i encountered was not sqlite-net-extensions related, but i'm keeping the question for context.
[Old Question]
I've got a problem with TwinCoders SQLite-net extensions.
I'm trying to insert a Series object into my database:
I'm using the Db.InsertWithChildren(SelectedSeriesObject,recursive:true) method.
The Series object is added accordingly with it's attributes.
All the Episodes are added as well, no problems there.
The problem is the BaseSeason.
It will only insert one Season object, which is (for some reason) the last Season Object of the list of Seasons in the Series
public class BaseSeries : BaseMedia
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[Indexed]
public int ShowId { get; set; }
public string FirstAirDate { get; set; }
public string LastAirDate { get; set; }
public string Status { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseSeason> Seasons { get; set; }
/// <summary>
/// TvShow = 0, Anime = 1
/// </summary>
public int SeriesType { get; set; }
}
public class BaseSeason
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeries))]
public int SeasonId { get; set; }
public int SeasonNumber { get; set; }
public int NumberOfEpisodes { get; set; }
public string Plot { get; set; }
public string Poster { get; set; }
public string AirDate { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BaseEpisode> Episodes { get; set; }
[ManyToOne]
public BaseSeries BaseSeries { get; set; }
}
public class BaseEpisode
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(BaseSeason))]
public int EpisodeId { get; set; }
public string Title { get; set; }
public string Plot { get; set; }
public string Poster { get; set; } //still path
public string AirDate { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string SeriesName { get; set; }
[ManyToOne]
public BaseSeason BaseSeason { get; set; }
}
Is there anyone with experience regarding nested relationships in sqlite-net-extensions that knows how to make this work or see what i did wrong?
So regarding writing nested lists in sqlite-net-extensions:
My problem turned out the be related to how I handle the creation of these objects, this is by no means related to sqlite-net extensions. So my bad!
Which means that the questions example is valid and works. (I tested it of course)
Setting up the entities for the database:
The example shown in my question, with a Series class, Season class and Episode class, is the correct way of setting it up.
Inserting into the database:
If you're wondering how to insert an object similar to my Series object (with nested lists), use:
db.InsertWitchChildren(yourObject, recursion: true)
Here's an extended example:
public void AddSeries()
{
MediaDB.db.CreateTable<BaseSeries>();
MediaDB.db.CreateTable<BaseSeason>();
MediaDB.db.CreateTable<BaseEpisode>();
MediaDB.db.InsertWithChildren(SelectedSeries, recursion: true);
}
Side Note:
The example uses a static property on class with the connection string. Like so:
public class MediaDB
{
public static SQLiteConnection db => new SQLiteConnection(new SQLitePlatformGeneric(),"Media.db");
}
Refrain from doing this it is not really the best thing to do, since you should use using for the SQLiteConnection, making sure it's disposed once you're done with it.
more info on: sqlite-net-extentions
[UPDATE]: Further expansion of handling nested lists in sqlite-net extensions:
Deleting tables with children:
This is quite simple, but i spent a good hour and half figuring it out anyways.
Just use:
For lists/arrays: db.DeleteAll(yourCollection, recursion: true)
For single objects: db.Delete(yourObject, true);
As an exmaple: here's my implementation of a method that will delete a List
(BaseSeries is the class shown in the original question question):
public static void RemoveCollection<T>(List<T> collection)
{
using (db)
{
if (typeof(T) == typeof(BaseMovie))
{
db.DeleteAll(collection);
}
if (typeof(T) == typeof(BaseSeries))
{
db.DeleteAll(collection, recursion: true);
}
}
}
The BaseMovie class is a simple single entity, recursion is not needed since it holds no children.
I'm trying to get data in a suitable format for an api
What I would like is
Place
--Rating1
---RatingImage1.1
---RatingImage1.2
---UserName
---UserId
--Rating2
---RatingImage2.1
---RatingImage2.2
---UserName
---UserId
In a nutshell im trying to fetch a place, with its ratings(and rating images), with the names of the users who did the rating given the googlePlaceId
Tried this but it goes and does some circular fetching where once it fetches the user it then fetches the user rating and the response becomes massive
context.Places
.Include(x => x.Ratings.Select(y => y.User))
.Include(x => x.Ratings.Select(c => c.RatingImages))
.Single(x => x.GooglePlaceId == googlePlaceId);
I think projection or linq joins must be the way, but i havent had any success yet.
here are my POCOS
Place Poco
public class Place
{
public Place()
{
Ratings = new List<Rating>();
Favourites = new List<Favourite>();
}
public int Id { get; set; }
public string Name { get; set; }
public string GooglePlaceId { get; set; }
public ICollection<Rating> Ratings { get; set; }
public ICollection<Favourite> Favourites { get; set; }
}
Rating POCO
public class Rating
{
public Rating()
{
RatingImages = new List<RatingImage>();
}
public int Id { get; set; }
public float RatingValue { get; set; }
public string RatingComment { get; set; }
public int PlaceId { get; set; }
public Place Place { get; set; }
public string UserId { get; set; }
public AspNetUser User { get; set; }
public ICollection<RatingImage> RatingImages { get; set; }
}
User POCO
public partial class AspNetUser
{
public string UserName { get; set; }
public string Id { get; set; }
// the rest of the fields are omitted
}
Although you've omitted the definition of AspNetUser, I'm guessing it has a navigation property back to Ratings. Is this required anywhere else in your application? It won't affect the structure of your database, and removing it would allow your projection to work exactly as you've got it here. You'd still be able to display all ratings by a single user using a separate query - you've got to optimise for your most common scenario though.
here is the object model.When i try to commit Product to Solr, returning unknown field loca
public class Product
{
[SolrUniqueKey("id")]
public string Id { get; set; }
[SolrField("manu")]
public string Manufacturer { get; set; }
[SolrField("cat")] // cat is a multiValued field
public ICollection<string> Categories { get; set; }
[SolrField("price")]
public decimal Price { get; set; }
[SolrField("inStock")]
public bool InStock { get; set; }
[SolrField("loca")]
public Location Location { set; get; }
}
public class Location
{
[SolrField("zipcode")]
public int Zip { set; get; }
[SolrField("country")]
public string Country { set; get; }
}
Is nested classes legal with solr?
why is it failing to store? when i remove [SolrField("loca")] it works fine.
how do you store such classes?
You cannot do nested classes in Solr. So you will need to flatten the location information into the Product class. However, you can then represent it a nested class within your application, by mapping the data into/out of Solr as needed.
As an example, update your Solr schema to store a loca_zipcode and loca_country field and then map those perhaps in a new SolrProduct class defined like the following:
public class SolrProduct
{
[SolrUniqueKey("id")]
public string Id { get; set; }
[SolrField("manu")]
public string Manufacturer { get; set; }
[SolrField("cat")] // cat is a multiValued field
public ICollection<string> Categories { get; set; }
[SolrField("price")]
public decimal Price { get; set; }
[SolrField("inStock")]
public bool InStock { get; set; }
[SolrField("loca_zip")]
public int Zip { set; get; }
[SolrField("loca_country")]
public string Country { get; set; }
}
Then you can use something like AutoMapper to map the SolrProduct flattened class to your Product class with the nested Location class.
Another alternative would be to use dynamic fields in Solr and the dynamic mapping support in SolrNet using a Dictionary. Please see the SolrNet - Mapping section of the SolrNet wiki for more details and examples.