How to prevent cyclic response with DBSet.Add() in Entity Framework? - c#

I'm working with an ASP.NET Core 6.0 Web API using EF Core 7.0. Mostly, it's working well but I am stuck on something I can't quite figure out.
In my service layer, I am passing in a FooForCreationDto and manually mapping it to a Foo. The Foo object gets passed to the repo which calls Context.Set<T>().Add(object);
Fine.
But, the Foo object has a many-to-many relationship with a Bar object. So each object has a list of the other object. The problem is that the add method returns an object with a cyclic error, returning each objects list of the other, recursively. I want the add to just return Foo and its list of Bars, not to then also include each Bar's list of Foo's and so on, round and round.
The repo method is generic, so this should also work the other way around when adding a new Bar.
In a get method, we would have to use .Include(x => x.Bar) to include nested objects, but the return object of the Add method seems to do this by default.
How can I disable this?
I think the above is pretty clear, but here is a code example:
// Models
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public List<Bar> Bars { get; }
}
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
public List<Foo> Foos { get; }
}
// Service
public async Task<Foo> CreateFoo(FooForCreationDto fooForCreation)
{
Foo foo = new Foo()
foo.name = fooForCreation.name //map top level props.
if (!fooForCreation.Bars.IsNullOrEmpty())
{
var bars = (List<Bar>)await _repository.Bar.GetBarsFromIds(fooForCreation.Bars);
foo.Bars.AddRange(bars);
}
// everything is fine to here. Foo has a list of Bar, but Bar does not contain nested recursive Foos
_repository.Foo.CreateFoo(foo);
//At this point foo now has nested bars with nested foos with nested bars etc... even though createFoo has void return.
await _repository.SaveAsync();
return foo
}
// Repository : RepositoryBase
public void CreateFoo(Foo foo)
{
Create(foo);
}
// RepositoryBase<T>
public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected MyDb RepositoryContext;
public RepositoryBase(MyDb repositoryContext)
=> RepositoryContext = repositoryContext;
//This add method returns foo with recursive bars and foos, which then changes what is returned from the service method.
public void Create(T entity) => RepositoryContext.Set<T>().Add(entity);
}
I had a go adding the Microsoft.EntityFrameworkCore.Proxies and then adding UseLazyLoadingProxies, and then marking the lists in the model classes as virtual, but this seemed to cause all sorts of other errors I've not managed to unpick yet. For example, even it throws cyclic errors even though I have
JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Ignore

Related

C# How to return an instance of the type of subclass from function?

I have a bunch of classes that formulate various variations of items. I currently have a class like this:
public class Item {
public ItemFile file { get; set;}
public ItemCalendar calendar { get; set;}
public ItemWebsite website { get; set;}
}
ItemFile etc are classes made using Entity Framework and map to the database tables that provide the information relating to that type of item. The item class only has one of the internal properties actually instantiated.
I can see the number of items growing to around 25 or more. I don't feel right making the view model containing 25 properties where 24 of them are null with only one being not null.
I want something that can work with entity framework and return a class that can return only it's actual type. Therefore if I ask for the variation of the item I would get back ItemFile for files and ItemCalendar for calendars.
I've tried something like this:
public class Item
{
public ItemBase item { get; set; }
}
public class ItemBase
{
public Type typeName { get; set; }
public object ItemInstance { get; set; }
public typeName GetInstance()
{
return Convert.ChangeType(ItemInstance, typeName);
}
}
But then I don't know how to return ItemFile as public typeName is an error.
I then tried:
public class Item
{
public ItemBase<ItemFile> item { get; set; }
}
public class ItemBase<T>
{
public T ItemInstance { get; set; }
}
But to get that to work, I had to hardcore FileItem in the <> on the item class which goes back into knowing the type before hand.
Is there anyway to get this to work? Bonus points if it can work with entity framework as I'm pulling back the classes from there. Worst comes to worst if it doesn't work entity framework wise is I can pull it all and then convert it into the form that answers the question.
If the title of the question is wrong, feel free to edit. I wasn't sure how to ask.
tl;dr version: I want to be able to return multiple types of classes from a function using a type that is passed in not using <>.
Edit 1:
I forgot to show my inheritence example. I've tried this but also got stuck with something similar to the above.
public class ItemBase
{
public Type typeName { get; set; }
public object ItemInstance { get; set; }
public typeName GetInstance()
{
return Convert.ChangeType(ItemInstance, typeName);
}
}
public class ItemFile : ItemBase
{
public String FileName { get; set; }
}
public class Test
{
public void testFunction()
{
//Made this just so the compiler didn't complain.
ItemFile testFile = new ItemFile();
//I can use a function to get the item base.
ItemBase baseItem = testFile;
//How do I do this? Use a function to get the ItemFile from the instance.
ItemFile finalItem = baseItem.GetInstance();
}
}
I want to be able to return multiple types of classes from a function using a type that is passed in not using <>.
<> (generics) are the mechanism by which a function can explicitly return more than one type. Without generics the function returns whatever type it says it returns.
object SomeFunction() // Returns an object
ItemBase SomeOtherFunction () // returns ItemBase
In the above examples, SomeFunction can still return any type (because all types inherit from object.) But it won't be explicit. All you know for sure is that it's an object.
Similarly, SomeOtherFunction can return an ItemBase or any class that inherits from ItemBase. But that's all you know about it.
Ideally you don't want to have functions returning one type (like object or ItemBase) and then cast the result of the function to another more specific type. The function should return what you want, and you should want what the function returns. Generics help with that. For example:
public TItem Instance<TItem>() where TItem : ItemBase
allows a function to return a specified type as long as it is an ItemBase or inherits from one.
This last comment is going to seem odd or useless but it's the truth. If you find yourself in a scenario where the above rules don't work and you need to be able to do something that you can't do or shouldn't do, go back and rethink why you're trying to do that. That's where the real problem is.
That means you probably need to go back a step and get yourself out of the situation where you're trying to work against the language. What are you trying to accomplish and how can you do it in a way that works with the language, not against it?
I believe this is about as close as you're going to get.
using System;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
EFTypeData itemData = GetItemData();
var asmName = Assembly.GetExecutingAssembly().GetName().Name;
var type = Type.GetType($"ConsoleApplication1.{itemData.TypeName}, {asmName}");
var instance = Activator.CreateInstance(type);
var item = new Item<Object>()
{
ItemBase = instance
};
}
private static EFTypeData GetItemData()
{
return new EFTypeData() { TypeName = "ItemFile" };
}
}
class EFTypeData
{
public string TypeName { get; set; }
}
class Item<T> where T: class
{
public T ItemBase { get; set; }
}
class ItemFile
{
public string FileName { get; set; }
}
}
This will, given a string "ItemFile", create an instance and assign it to Item. If you run this and inspect item, you have
The big caveat to this is that at compile-time, all you have is an Object as your ItemBase. And without hard-coding your Type (i.e. var item = new Item<ItemFile>();), you're never going to know more.
That said, with this method you are perfectly clear to iterate over fields and such using Reflection. But this is a limitation of this level of run-time object manipulation.

Moq for single line multiple property code

I have these interfaces
public interface Interface1 { Interface2 Items {get;} }
public interface Interface2 { Guid? ApplicationTypeId { get; } }
public interface Interface3 { Class1 Item {get;} }
public interface Interface4 { Guid? ApplicationId { get; set; } }
A class inherits the first interface
public class Class1 : Interface1 {
public Interface2 Items { get; }
}
Another class which consists of few guids
public static class ContentTypeIds
{
public static Guid ContentGuid1 => new Guid("{11798e9d-a167-4cfc-8cfa-9a24fd6caf25}");
public static Guid ContentGuid2 => new Guid("{7d22f5bb-37fd-445a-b322-2fa1b108d260}");
}
I need to unit test the following property
private readonly Interface3 _interface3;
public Ticket Current
{
get
{
//This line is very complicated
Interface4 itemByContentType = _interface3.Item?.Items.GetItemByContentType(ContentTypeIds.ContentGuid2);
if ( itemByContentType?.ContentId != null )
return Get(itemByContentType.ContentId.Value);
return null;
}
}
My test class goes here
[Test]
public class TestClass {
var mock1 = new Mock<Interface1>();
var mock2 = new Mock<Interface2>();
var mock3 = new Mock<Interface3>();
mock1.SetupAllProperties();
mock2.SetupAllProperties();
mock3.SetupAllProperties();
}
The value for 'itemByContentType' goes null.
Could anyone help me to make it simple and testable as it is getting complicated to test this property? I'm using Moq. I will appreciate any help.
Thanks
I'm not an expert on Moq, but it looks like its SetupAllProperties method simply sets up all the properties to act like properties (i.e. the object it creates has a persistent member which can support GET/SET operation). If this isn't done, then as I understand it, the properties will still be available, but they'll always resolve to null. This is very handy when preparing the Mock objects, but on its own, though, that doesn't setup the properties with any sort of value.
I think what you should be doing is using Moq's SetupGet in conjunction with the Returns method to prepare the GET of the Items property with a specific value.
Here is some (simplified) sample code, to demonstrate this:
public interface IFoo { Guid? ApplicationId { get; set; } }
public interface IBar { IFoo Items { get; } }
class Program
{
static void Main(string[] args)
{
// SETUP
// Prepare mocks
Mock<IFoo> MockFoo = new Mock<IFoo>();
Mock<IBar> MockBar = new Mock<IBar>();
// Seting up properties allows us read/write Foo's ApplicationId
MockFoo.SetupAllProperties();
// The mocked Foo object should be what's returned when Items is requested
var expectedFoo = MockFoo.Object;
// Setup the Bar object to return that mocked Foo
MockBar.SetupGet(x => x.Items).Returns(expectedFoo);
// The value written here will be persistent due to SetupAllProperties
expectedFoo.ApplicationId = new Guid("{7d22f5bb-37fd-445a-b322-2fa1b108d260}");
// ACTION
// When the "Items" property is accessed, the IFoo we get should be what we mocked...
var actualFoo = MockBar.Object.Items;
// ... and we can read the value set to Foo's ApplicationId
var actualAppId = actualFoo.ApplicationId;
}
}

Object referenced by many, without own property

I have a class that is referenced by many other classes:
class Foo
{
// Some properties
}
class Bar
{
public Foo Foo { get; set; }
}
I can map this relationship on the Bar end:
class BarMap : ClassMap<Bar>
{
public BarMap()
{
References(b => b.Foo).Cascade.All();
}
}
This works when I am deleting a Bar object but I am getting foreign key conflicts if I try and delete a Foo object. I understand this is because NHibernate doesn't know that there are Bars relying on it, so happily tries to delete the Foo and not the Bars.
I know I can do something along the lines of:
class Foo
{
public IList<Bar> Bars { get; set; }
// some properties
}
class FooMap : ClassMap<Foo>
{
public FooMap()
{
HasMany(f => f.Bars)
.Inverse()
.Cascade.AllDeleteOrphans();
}
}
Is there a way to map Foo so that it knows about the inverse many-to-one relationship without adding a property to Foo? I don't really want to add a collection to Foo for each type of object referencing it.
I think I have correctly understood your aim, and I fear the answer is you cannot do that easily.
You may try using IInterceptor or event combined with some analysis of the meta-model NHibernate has generated from your mapping (see ISessionFactory.GetAllClassMetadata), but this would probably requires a bunch of work hours.

Is there a way to dial down the OData Service reflection provider?

This is a continuation of an issue I'm still experiencing here. I'm trying to prevent the OData reflection provider from trying to expose ALL of the CLR classes in my assembly.
Consider the following CLR class:
public class Foo
{
public Guid FooID { get; set; }
public string FooName { get; set; }
}
And the following class to expose Foo as an IQueryable collection:
public class MyEntities
{
public IQueryable<Foo> Foos
{
get
{
return DataManager.GetFoos().AsQueryable<Foo>();
}
}
}
And the following DataService class:
public class MyDataService : DataService<MyEntities>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Foos", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
This all works hunkey dorey and the DataService can display a collection of Foo. But if change Foo to extend a very simple base object such as:
public class Foo : MyObjectBase
{
public Guid FooID { get; set; }
public string FooName { get; set; }
}
Then (even though I'm only trying to expose 1 collection), the reflection provider grabs ALL objects that extend MyObjectBase, causing loads of errors.
The base class is a simple abstract class that implements a number of interfaces and provides another property such as:
public abstract class MyObjectBase: IDataObject, IDataErrorInfo, INotifyPropertyChanged, IDisposable
{
public virtual Guid ID { get; set; }
}
Even putting IgnoreProperties on any public properties here doesn't help. Is there any way to dial down what the reflection provider is doing?
You could set:
config.SetEntitySetAccessRule("TypeNotAccessible", EntitySetRights.All);
to
config.SetEntitySetAccessRule("TypeNotAccessible", EntitySetRights.None);
On any classes you don't want accessible. I do this using the help of a custom attribute that indicates the rights I want for a particular class. This in combination with looping over all known types (that implement my attribute), makes it possible to do this without explicit code to set each class individually.
I was unable to find a way to dial down the reflection provider with a rich data model. I ended up building a custom provider as indicated here.
If someone provides a way to dial down the reflection provider, I'll accept that answer.

Castle Windsor Dependency Injection - restore dependencies for existing instance

I have a fairly straight-forward scenario that I am trying to solve but I'm hitting a few brick walls with Windsor - perhaps I'm trying to solve the problem in wrong way?
I have a type called Foo as follows:
public class Foo
{
[NonSerialized]
private IBar bar;
public IBar Bar
{
get { return this.bar; }
set { this.bar = value; }
}
public Foo(IBar bar)
{
}
}
I instantiate via the container in the normal way:
var myFoo = container.Resolve<Foo>();
The dependency IBar is registered with the container and gets resolved when the object is created. Now that the type has been created, I need to serialize it and I don't want to serialize IBar so it's marked with a NonSerialized attribute.
I then need to deserialize the object and return it to it's former state. How do I achieve this with Castle Windsor? I already have an instance, it is just missing it's dependencies.
If I was using Unity, I would use BuildUp() to solve the problem, but I want to use Castle Windsor in this case.
It seems like Foo is having multiple concerns. Try to separate the data part from the behavior by creating a new class for the data and use it as a property in the Foo class:
[Serializable]
public class FooData
{
}
public class Foo
{
private FooData data = new FooData();
public IBar Bar { get; private set; }
public FooData Data { get; set; }
public Foo(IBar bar)
{
}
}
When you have this construct in place you can deserialize FooData and use it in a created Foo:
var foo = container.Get<Foo>();
foo.Data = DeserializeData();

Categories