Kotlin DTO Entity mapping recursion problem - spring

So I'm tring to map a Dto to Entity and vice versa but since I have a bidirectional connection between them I run into a recursion error is there an easy fix for this I just started using kotlin and have not found any solutions yet.
These are my extension classes.
RegistrationRuleExtension.kt
fun RegistrationRuleEntity.toDto() = RegistrationRuleDto(
id = id,
count = count,
description = description,
tier = tier,
licenses = licenses?.map { license -> license.toDto()}
)
fun RegistrationRuleDto.toEntity() = RegistrationRuleEntity(
id = id,
count = count,
description = description,
tier = tier,
licenses = licenses?.map { license -> license.toEntity()}
)
LicenseExtension.kt
fun LicenseEntity.toDto() = LicenseDto(
id = id,
name = name,
licenseId = licenseId,
rules = rules?.map { rule -> rule.toDto() },
version = version
)
fun LicenseDto.toEntity() = LicenseEntity(
id = id,
name = name,
licenseId = licenseId,
rules = rules?.map { rule -> rule.toEntity() },
version = version
)
If I understand it right the problem is that my license call the for the .toDto on my rule and then the rule wants to call the .toDto on my license and it gets into an infinite loop.
Thanks for the answers in advance!

So there were a few ideas I got from friends and coworkers.
My first idea:
Since the licence knows which rules it has there is not really a reason for me to get the licenses on the rules therefor I can just set it null in my case.
The second idea:
I only store the ids of the rules on the licence and if I need the rule I request them by their ids.
If you have any other ides feel free to comment it ect. :D

Related

Why could the F# LINQ expression not be translated - at least partially?

Issue
I’m using an existing code first approach in order to acquire data from an existing database. This project is encapsulated in a .NET C# project and contains the model as well as the configuration descriptions.
My aim is to use the existing database context implementation for a F# project. I have been testing many times the database access with a XUnit test project which is also written in F#.
My problem is an unexpected behaviour, when I try to select the last name and the person’s id.
In order to explain my implementation and illustrate the issue I implemented four test functions of which only the first two are executed successfully. The last two test functions fail.
The following error appears
System.InvalidOperationException : The LINQ expression 'LastName' could not
be translated. Either rewrite the query in a form that can be translated, or
switch to client evaluation explicitly by inserting a call to 'AsEnumerable',
'AsAsyncEnumerable', 'ToList', or 'ToListAsync'*
I do not understand the error because I am not actually using any client specific implementation for the query evaluation. So normally the LINQ-Provider should convert it into a database appropriate SQL definition. For the tests I am using the Entity Framework memory database instance. On top of that, please note that the error also exists on the real database.
Another issue that I do not understand is why the second test works while the third one fails. I changed only the last name select with the id select.
However, I also added a F# query expression since this is actually recommended from the documentation, but with no success.
Is the main problem the usage of the Entity Framework context? If so, how can I then reuse the implementation of the EF database context?
Test and evaluation with LINQPad 6
I tested the behaviour with LINQPad in order to make the use case more simple. Therefore, I used the DemoDB which should be available for everyone.
Apart from that I’m trying to make it reproduceable for a larger community. Unfortunately, the outcome of my test is the same. So, I created a simple database query and changed the order of the named selections. If I change the alphabetical order of the column names, the error appears. Therefore, why is the alphabetical order important in order to have a valid select statement?
I found another closed issue on stackoverflow which describes the usage of anonymous records but the different order is not treated (F# Query Expression / select operator / changing column headings in result).
// successful query
query {
for c in this.Categories do
select {| A = c.CategoryID; B = c.CategoryName; |}
}
// failed query
query {
for c in this.Categories do
select {| B = c.CategoryID; A = c.CategoryName; |}
}
The argument 'value' was the wrong type. Expected
'System.Func`2[System.Int32,<>f__AnonymousType1383943985`2[System.String,System.Int32]]'.
Actual '<>f__AnonymousType1383943985`2[System.String,System.Int32]'.
Test and evaluation with a F# unit test project
Test result summary
I tested the behaviour with .NET 3.1 and .NET 5.0 (projects as well as LINQPad 6). Furthermore, all dependencies have been adjusted accordingly (e.g. Entity Framework 5.0 or 3.1).
Test
Result
A anonymous record
successful
B anonymous record
successful
C anonymous record
failed
D anonymous record
failed
E partial person type
failed
F partial person type
successful
G partial person type
successful
H partial person type
failed
I partial person type
failed
Test outcome
System.InvalidOperationException : The LINQ expression 'LastName' could not be translated. Either rewrite the query in a form that can be translated, or switch
to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
Entity Framework Core "5.0.3" initialized
'"TestContext"' using provider '"Microsoft.EntityFrameworkCore.InMemory"'
EF core code first database .NET 5 project
public class Person
{
public int Id { get; set; }
public string LastName { get; set; }
}
...
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.ToTable("PERSON");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasColumnName("ID")
.ValueGeneratedNever();
builder.Property(x => x.LastName)
.HasColumnName("LASTNAME")
.HasMaxLength(512)
.IsUnicode(false);
}
...
public class TestContext : DbContext
{
public DbSet<Person> Persons { get; private set; }
public TestContext(DbContextOptions<TestContext> options) : base(options)
{}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new PersonConfig());
}
}
F# xunit test project in order to evaluate the EF core database context access
type PartialPerson = { LastName: string; ID : int; }
type ``success database execution queries`` (output: ITestOutputHelper) =
let sLogger =
LoggerConfiguration()
.MinimumLevel.Verbose()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.TestOutput(output, Events.LogEventLevel.Verbose)
.WriteTo.Debug()
.CreateLogger()
let loggerFactory =
(new LoggerFactory())
.AddSerilog(sLogger)
let options = DbContextOptionsBuilder<TestContext>()
.EnableSensitiveDataLogging(true)
.UseLoggerFactory(loggerFactory)
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
let context = new TestContext(options)
[<Fact>]
let ``success person select lastname Test A`` () =
let rs =
context.Persons.Select(
fun person -> {| Name = person.LastName |} )
rs |> should be Empty // successful
[<Fact>]
let ``success person select id and lastname Test B`` () =
let rs =
context.Persons.Select(
fun person ->
{| ID = person.Id
LastName = person.LastName |})
rs |> should be Empty // successful
[<Fact>]
let ``success person select id and lastname Test C`` () =
let rs =
context.Persons.Select(
fun person ->
{| LastName = person.LastName
ID = person.Id |} )
rs |> should be Empty // failed
[<Fact>]
let ``success person select id and lastname Test D`` () =
let rs =
query {
for person in context.Persons do
select
{| LastName = person.LastName
ID = person.Id |}
}
rs |> should be Empty // failed
// avoid anonymous record and use the partial person type
// type PartialPerson = { LastName: string; ID : int; }
[<Fact>]
let ``success partial person select id and lastname Test E`` () =
let rs =
context.Persons.Select(
fun person ->
{ ID = person.Id
LastName = person.LastName })
rs |> should be Empty // failed
[<Fact>]
let ``success partial person select id and lastname Test F`` () =
let rs =
context.Persons.Select(
fun person ->
{ LastName = person.LastName
ID = person.Id } )
rs |> should be Empty // successful
[<Fact>]
let ``success partial person select id and lastname Test G`` () =
let rs =
query {
for person in context.Persons do
select
{ LastName = person.LastName
ID = person.Id }
}
rs |> should be Empty // successful
[<Fact>]
let ``success partial person select id and lastname Test H`` () =
let rs =
query {
for person in context.Persons do
select
{ ID = person.Id
LastName = person.LastName }
}
rs |> should be Empty // failed
[<Fact>]
let ``success partial person select id and lastname Test I`` () =
let rs =
query {
for person in context.Persons do
select
{ ID = person.Id
LastName = person.LastName }
}
rs.ToList() |> should be Empty // failed
Current findings
It seems that this issue is related to the issues 1226 and 3782. Both issues describe some problems with the order of named selections.
The dapper issue 1226 had a similar problem with the order of anonymous records for the query definition. However, thanks to Isaac Abraham (isaacabraham) who is using the CLIMutable decoration, I thought of turning off the ordering restrictions. So basically the idea was to try it for my tests since the query generation through the LINQ provider could have a positive effect. Unfortunately this was without success, maybe because of the implementation of the LINQ provider because the generation process is implemented with F# and that is the reason why the CLIMutable attribute does not affect it.
After continuing my search, I found another issue 3782 which indicates my problem. The issue has the main focus on the usage of tuples for the data selection but also the issue with records. So, I added another issue description 11131 in order to help with my current findings. Finally, I will keep track the outcome and add it to this issue.
Does this still need answering?
As you already found out, F# anonymous types order fields by name (not by source code order of declaration, as C# anonymous types would do).
When writing {| B = c.CategoryID; A = c.CategoryName; |} in a LINQ query, this will not actually pass an anonymous type, rather the compiler creates an System.Linq.Expressions.Expression that describes how to construct the anonymous type, and later on the underlying framework implementing LINQ (e.g., the Entity Framework) will try to parse that expression (and create e.g. SQL code from it).
Problem here is, c.CategoryID and c.CategoryName may have side effects, hence the compiler will evaluate them in the order specified in the source code (first ID, then Name), but assign them in the order of the anonymous type.
Long story short, the generated System.Linq.Expressions.Expression first will evaluate c.CategoryID, assign the value to a temporary variable, evaluate c.CategoryName, assign that to the anonymous type's first field, and finally assign the temporary variable to the anonymous type's second field. And the EF translator later on does not know how to handle the temporary variable (e.g., how to translate that to SQL.)
(In C#, no field reordering happens, so no temporary variables are required to mask side effects, so the expression parser will not face that problem.) (The F# anonymous type at present is not fully fit for LINQ.)

Query on an entity, where joined with another that has a specific value?

I have a database with 3 tables.
LANGUAGE
id
ARTICLE
-id
ARTICLE_DETAIL
-id
-articleId
-languageId
I need to get an article from the database, but only if it has article details in a specific language. Today, I have the query in native MySQL using a coalesce, and that works fine. But now I want to make the same thing in EJB3. I've tried a lot of different things, but so far unsuccessful. I'm not very familiar working with entities in EJB3, so if anyone could please help me getting on the right track here, I would appreciate it.
Here's more or less what I've been trying so far:
Integer id = 543; // id of an article
Integer languageId = 2; // id of a language
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Article> cq = cb.createQuery(Article.class);
Root<Article> article = cq.from(Article.class);
Join<Article, ArticleDetail> details = article.join(Article_.articleDetailList);
// I think this is where I go wrong
cq.where(article.get(Article_.id).in(id)).where(details.get(ArticleDetail_.languageId).in(languageId));
TypedQuery<Article> q = em.createQuery(cq);
Article result = (Article) q.getSingleResult();
return result;
This did the job:
...
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Article> cq = cb.createQuery(Article.class);
Root<Article> article = cq.from(Article.class);
Join<Article, ArticleDetail> details = article.join(Article_.articleDetailList);
Join<ArticleDetail, Language> language = details.join(ArticleDetail_.languageId);
cq.where(cb.and(
cb.equal(article.get(Article_.id), id),
cb.equal(language.get(Language_.id), languageId)));
...

Can't combine "LINQ Join" with other tables

The main problem is that I recieve the following message:
"base {System.SystemException} = {"Unable to create a constant value of type 'BokButik1.Models.Book-Author'. Only primitive types ('such as Int32, String, and Guid') are supported in this context."}"
based on this LinQ code:
IBookRepository myIBookRepository = new BookRepository();
var allBooks = myIBookRepository.HamtaAllaBocker();
IBok_ForfattareRepository myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var Book-Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer();
var q =
from booknn in allBooks
join Book-Authornn in Book-Authors on booknn.BookID equals
Book-Authornn.BookID
select new { booknn.title, Book-AuthorID };
How shall I solve this problem to get a class instance that contain with property title and Book-AuthorID?
// Fullmetalboy
I also have tried making some dummy by using "allbooks" relation with Code Samples from the address http://www.hookedonlinq.com/JoinOperator.ashx. Unfortunately, still same problem.
I also have taken account to Int32 due to entity framework http://msdn.microsoft.com/en-us/library/bb896317.aspx. Unfortunatley, still same problem.
Using database with 3 tables and one of them is a many to many relationship. This database is used in relation with entity framework
Book-Author
Book-Author (int)
BookID (int)
Forfattare (int)
Book
BookID (int)
title (string)
etc etc etc
It appears that you are using two separate linq-to-sql repositories to join against. This won't work. Joins can only work between tables defined in a single repository.
However, if you are happy to bring all of the data into memory then it is very easy to make your code work. Try this:
var myIBookRepository = new BookRepository();
var myIBok_ForfattareRepository = new Bok_ForfattareRepository();
var allBooks =
myIBookRepository.HamtaAllaBocker().ToArray();
var Book_Authors =
myIBok_ForfattareRepository.HamtaAllaBok_ForfattareNummer().ToArray();
var q =
from booknn in allBooks
join Book_Authornn in Book_Authors
on booknn.BookID equals Book_Authornn.BookID
select new { booknn.title, Book_AuthorID = Book_Authornn.Book_Author };
Note the inclusion of the two .ToArray() calls.
I had to fix some of you variable names and I made a bit of a guess on getting the Author ID.
Does this work for you?
I would suggest only having a single repository and allowing normal joining to occur - loading all objects into memory can be expensive.
If you are making custom repositories you make also consider making a custom method that returns the title and author IDs as a defined class rather than as anonymous classes. Makes for better testability.

How do I programmatically translate a LINQ query to readable English text that correctly describes the linq expression?

I am working on a project that uses Albahari's PredicateBuilder library http://www.albahari.com/nutshell/ to create a linq expression dynamically at run time. I would like to find a way to translate this dynamically created linq predicate of type Expression<Func<T, bool>> into a readable english statement at runtime.
I'll give a statically created linq statement as an example:
from p in Purchases
select p
where p.Price > 100 && p.Description != "Bike".
For this linq statement I would want to dynamically generate at runtime an english description along the lines of:
"You are searching for purchases where the price is greater than 100 and the description is not bike".
Are there any libraries that already exist which accomplish this goal, keep in mind I am using PredicateBuilder to dynamically generate the where predicate. If no solution exists how would you go about building a solution?
Thanks!
This caught my attention so I downloaded ExpressionSerializationTypeResolver.cs and ExpressionSerializer.cs and then I:
class Purchase
{
public decimal Price {get;set;}
public string Description {get;set;}
}
...
var purchases = new List<Purchase>() { new Purchase() { Price = 150, Description = "Flute" }, new Purchase() { Price = 4711, Description = "Bike" } };
Expression<Func<IEnumerable<Purchase>>> queryExp = () => from p in purchases
where p.Price > 100 && p.Description != "Bike"
select p;
ExpressionSerializer serializer = new ExpressionSerializer();
XElement queryXml = serializer.Serialize(queryExp);
and then I got into problems, but maybe you could do something with the pretty big expression tree of your query? You can find it here.

Subsonic 3 LINQ Projection issue, fixed or no?

I'm currently experiencing the issue mentioned here (and several other places): Subsonic 3 Linq Projection Issue
This is occurring using the 3.0.0.4 release package, and it also occurs when I grab the latest from GitHub and build it.
I am using the LINQ Templates.
I have this code:
var newModel = new ViewModels.HomeIndexViewModel() {
PulseListViewModel =
new ViewModels.PulseListViewModel
{
Pulses = from p in _pulseQuery
join a in _accountQuery on p.AccountId equals a.AccountId
orderby p.CreateDate descending
select new PulseListViewModel.Pulse()
{
AccountName = a.Name
, Category = p.Category
, CreateDate = p.CreateDate
, Link = p.Link
, Message = p.Message
, Source = p.Source
, Title = p.Title
}
}
};
But AccountName is always null.
If I change the AccountName to Name:
var newModel = new ViewModels.HomeIndexViewModel() {
PulseListViewModel =
new ViewModels.PulseListViewModel
{
Pulses = from p in _pulseQuery
join a in _accountQuery on p.AccountId equals a.AccountId
orderby p.CreateDate descending
select new PulseListViewModel.Pulse()
{
Name = a.Name
, Category = p.Category
, CreateDate = p.CreateDate
, Link = p.Link
, Message = p.Message
, Source = p.Source
, Title = p.Title
}
}
};
It works fine. But that's not acceptable in our project; I can't always make the names line up (besides the fact that it would make things less clear if I could).
But I'm quite confused because it would seem this issue's been fixed:
"Fixed issue where Projections were returning null or empty settings"
-- http://blog.wekeroad.com/2010/03/21/subsonic-3-0-0-4-released
So, can anyone tell me: Is this issue not fixed, and do I have to apply the changes found here at http://github.com/funky81/SubSonic-3.0/commit/aa7a9c1b564b2667db7fbd41e09ab72f5d58dcdb to make this work? Or am I missing something. Because looking through the current SubSonic source it appears this fix has been included. I feel like this should be simple and work, but instead I've spent an inordinate amount of time on it.
If you (me) modify SubSonic.Core according to the answer here: Subsonic 3.0 and linq
Then the projection works correctly.
However, I consider this a very bad solution as it requires forking a project and introducing an order of magnitude performance decrease.
Could you send me a little bit more code (especially what's behind _pulseQuery and _accountQuery) so I can fix this issue. Are you using SimpleRepository or the ActiveRecord approach or Query objects directly?
Reviving an old topic here, but in case someone searches for this later...
I also "fixed" this same issue, and put some explanation in the comments, in my fork on GitHub in this commit: https://github.com/rally25rs/SubSonic-3.0/commit/61af6aeb2ebb95f486d8df533bf13c8754d443e2
There is actually a slightly deeper issue here too. If you choose to use the "standard .NET built-in" projections, then some of the SubSonic unit tests start to fail, because SS does some extra stuff in its projection generation that the .NET projection doesn't do, so some of the expected functionality of SS doesn't work.
Personally, I think that, and the slower performance (though I haven't noticed a speed decrease) is a small price to pay for correct data.

Resources