I know this question was asked before but I couldn't find any solution for my issue.
I am developing a WebAPI with more than 10 Controllers which their methods access a server DB.
I am using Linq2SQL to write the queries and using Json to serialize the return to send it back to my application.
The problem is no matter how simple is the query it returns the self reference loop when serialize and this is happening in all controller methods. See one example below:
var retitems = dtcxapi.ListItems.AsQueryable()
.Where(i => i.IsActive == true && i.ListName.ToLower() == listName.ToLower()).ToList();
where dtcxapi is my DataContext and ListItems is my table.
When serialize it shows: Self referencing loop detected with type 'BV.IMSWEBAPI.User'. Path '[0].User1.Users1'.
But as I said this error will occur for any query in any controller methods. I tried already to use the ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore in mWeb config but it didn't fix.
Any help will be really appreciated.
Thanks
The only true way to fix this is to not return your Linq objects and instead return a DTO/Model that is not tied to your database. If you are returning your database objects, you will always run into self referencing loops because of Navigation properties.
You haven't mentioned if you are using .NET Core or .NET Framework, but if it's Core, it won't use web.config at all and instead you should modify your startup method :
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
But again, this is a bandaid, the correct solution is to use DTOs
More info : https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/
Related
I Have Create a DB in that I am Having Multiple tables having Relationship between them.
When a try to get data from my WEb app i get this error
"'Self referencing loop detected with type 'System.Data.Entity.DynamicProxies.PrescriptionMaster_2C4C63F6E22DFF8E29DCAC8D06EBAE038831B58747056064834E80E41B5C4E4A'. Path '[0].Patient.PrescriptionMasters"
I coudn't get why i am getting this error, and when i remove the relationships between tables i get proper data From it.
I have Tried other solutions like adding
"config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore; "
in Webconfig.cs but nothing has worked for me.
Please help me, what should I do ?
The only proper way to prevent this from happening is by not sending Entity Framework objects (which may contain such loops) into the JSON Serializer (which is not too good at knowing when to stop serializing).
Instead, create ViewModels that mimic the parts of the EF Objects that your Front End actually needs, then fill those ViewModels using the EF Objects.
A quick-and-dirty way is to just use anonymous objects, for example:
return new
{
Product = new
{
Id = EF_Product.Id,
Name = EF_Product.Name
}
};
A good rule-of-thumb is to only assign simple properties (number, bool, string, datetime) from the EF Objects to the ViewModel items. As soon as you encounter an EF Object property that is yet another EF Object (or a collection of EF Objects), then you need to translate those as well to 'simple' objects that are not linked to EF.
On the other end of the spectrum there are libraries such as AutoMapper. If you decide that you need actual ViewModel classes, then AutoMapper will help mapping the EF Objects to those ViewModels in a very structured way.
Just add this to the Application_Start in Global.asax:
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter
.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
It will ignore the reference pointing back to the object.
Background
I'm trying to create a function componentFromJson that can reconstitute a component graph from JSON. I took a simple approach where I'm using getMetaData in order to lookup the component properties to instantiate the right types.
The function would be used like: comp = componentFromJson(json, 'RootComponentType')
Problem
The problem is that the type of the properties are not necessarily fully qualified because namespaces may have been imported, as we can see below.
<cfimport path="some.namespace.Test">
<cfcomponent>
<cfproperty name="test" type="Test">
</cfcomponent>
When I'm trying to do createObject('Test') from the componentFromJson function context it's obviously failing because the calling context doesn't have the imports.
I have tried many different ways to resolve the problem, including temporarily defining the component factory function on the parent component dynamically and using invoke to call the factory function in the context of the parent CFC, but it doesn't work.
E.g.
<cfscript>
parentCmp = createObject('SomeCmp');
parentCmp.createComponent = function (type) {
return createObject(type);
};
childCmp = invoke(parentCmp, 'createComponent', { type = 'Test' });
</cfscript>
Horrible solution
The only way I can think of solving this issue right now is to parse the ColdFusion code of the CFC and extract the import statements, but I'm expecting this to be way too slow for the purpose. Not only that but this wouldn't cover all edge cases.
Ideas?
I'd like to know if someone has a better idea for solving this issue? Is there an entirely different approach I could take? There is probably a way to do this using the ColdFusion runtime classes, but I haven't figured it out yet.
Well, it turns out that it wasn't so hard when you knew the underlying mechanics of the ColdFusion runtime (which I had trouble to find initially).
I finally discovered that a ColdFusion component, which is represented as a coldfusion.runtime.TemplateProxy was encapsulating a coldfusion.runtime.CFPage instance which in turns has a createObject method.
Therefore, here's the solution I came up with using Java reflection:
<cfset host = new SomeComponent()>
<cfset pageField = createObject('java', 'coldfusion.runtime.TemplateProxy').getClass().getDeclaredField('page')>
<cfset pageField.setAccessible(true)>
<cfset page = pageField.get(host)>
<cfset test = page.createObject('Test')>
I've googled a lot and read as much as I can on the subject but I cannot find a direct answer to my question anywhere including here. My ZF2 application consists of roughly 7 different modules. 5 of the modules will need access to the same database configuration. The application itself has a database with roughly 124 different tables. So the idea here is to find the proper solution to write the least amount of code considering the setup.
What I'm trying to do is create a specific class to interface with the DB. Where the business logic is kept in the Module and note the controllers to keep everything more abstract and easier to maintain. By that I mean controller X should be able to create a new instance of for instance (Application\Model\DBInterface) and use the models functions to do inserts deletes updates joins selects and so forth. The reason I would like to do it this way is so that all modules installed can use the same interface without having to write endless DI statements everywhere. So what I will need is an example of how I can get the configuration for the DB (currently inside module.config.php + local.php(username / pw)) to be passed to the Application\Model\DBInterface dbConfig variable, and perhaps even an instance of the dbAdapter initialized from config if possible.
Alternatively I could potentially grab the configuration from the Application\Model\DBInterface if such a way exists.
If neither of the above is possible then I can always go back to the old way of doing things by reading an ini file for the db details and instantiating my db adapter that way.
Please keep in mind that I won't be injecting anything in the controllers as the controllers just use $db = new \Application\Model\DBInterface() so injecting into the controllers doesn't make much sense at all.
Is there a better way to do this / optimized / am I doing it completely wrong? Anyone able to share some details please. I've spent way too much time on this already and definitely need help.
Okay, so #Ocramius did just let me know what my misconception with the initializers was and helped me out a bit in understanding it. So here is a probably working solution to your Problem. My understanding about your problem is:
"How to get a DbAdapter set for all your Models implementing a DbInterface". This is how you'd do it:
Step 1: Create invokables for all classes implementing the DbInterface. Create a factory for the default Zend\Db\Adapter\Adapter and then create an initializer for your DbInterface
Module.php getServiceConfig()
return array(
'invokables' => array(
'application-model-one' => 'Application\Model\One',
'application-model-two' => 'Application\Model\Two'
),
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory'
),
'initializers' => array(
'DbInterfaceInitializer' => function($instance, $sm) {
if ($instance instanceof \Application\Model\DBInterface) {
$instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
}
},
)
)
The Zend\Db\Adapter\Adapter is using the top-level-configuration-array-key 'db' to automatically inject the dbParams
Step 2: Create your classes implementing your Interface
Application\Model(One|Two|N).php
namespace Application\Model;
class One implements DbInterface, \Zend\Db\Adapter\AdapterAwareInterface
{
/**
* #var \Zend\Db\Adapter\Adapter $dbAdapter
*/
protected $dbAdapter;
public function setDbAdapter(\Zend\Db\Adapter\Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
}
public function getDbAdapter() {
return $this->dbAdapter;
}
// More of your business logic or data here
}
Step 3: Access those classes with the ServiceLocator from your Controllers
SomeController.php someAction()
$dbOne = $this->getServiceLocator()->get('application-model-one');
$dbTwo = $this->getServiceLocator()->get('application-model-two');
// Adapter will automatically be injected
When accessing the invokable from the ServiceManager the initializer will be called. The initializer then will automatically call the Zend\Db\Adapter\Adapter, which in turn get's the parameters from the configuration key 'db'
You may get more information from once the tutorial Application as well as the blog of
samsonasik: ServiceManager Cheat-Sheet
I have been trying to retrofit an excellent implementation of EF that I found here. Unfortunately the code was written for code first implementation and I am using model first since I already have the database up and running with another application.
In the ObjectContextBuilder.cs file is the following method:
public ObjectContextBuilder(string connectionStringName, string[] mappingAssemblies, bool recreateDatabaseIfExists, bool lazyLoadingEnabled)
{
this.Conventions.Remove<IncludeMetadataConvention>();
_cnStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
_factory = DbProviderFactories.GetFactory(_cnStringSettings.ProviderName);
_recreateDatabaseIfExists = recreateDatabaseIfExists;
_lazyLoadingEnabled = lazyLoadingEnabled;
AddConfigurations(mappingAssemblies);
}
I assume the EDMX would contain the mappings that the previous method requires so I am attempting to add a simaliar method that would take in an ObjectContext of the EDMX like this:
public ObjectContextBuilder(string connectionStringName, ObjectContext context, bool recreateDatabaseIfExists, bool lazyLoadingEnabled)
{
this.Conventions.Remove<IncludeMetadataConvention>();
_cnStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
_factory = DbProviderFactories.GetFactory(_cnStringSettings.ProviderName);
_recreateDatabaseIfExists = recreateDatabaseIfExists;
_lazyLoadingEnabled = lazyLoadingEnabled;
}
And here is the calling method:
ObjectContextManager.InitStorage(new SimpleObjectContextStorage());
var context = ((IObjectContextAdapter)new SidekickEntities());
ObjectContextManager.Init("SidekickEntities", context.ObjectContext, true);
When execution gets to assigning _factory I get an error that states:
Unable to find the requested .Net Framework Data Provider. It may not be installed.
When I look at _cnStringSettings, the Provider is System.Data.SqlClient but when assigning _factory the _cnStringSettings.ProviderName is System.Data.EntityClient.
I assume this is because I am trying to use the Entity generated by the EDMX and would like to know if there is a way to get my new method to work. I am fairly new to the EF framework and am still in a steep learning curve so please let me know if I am completely off base on what I am trying.
Here is the connection string as it is stored in App.Config
<add name="SidekickEntities" connectionString="metadata=res://SidekickModel/SidekickModel.csdl|res://SidekickModel/SidekickModel.ssdl|res://SidekickModel/SidekickModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=percepsrvr;Initial Catalog=Sidekick;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
Having an existing database doesn't mean you have to use model first (fortunately). See Scott Gu's Using EF “Code First” with an Existing Database and the TechEd 2011 screencast Code First Development in Microsoft ADO.NET Entity Framework 4.1 for details. Worked pretty well for me.
I found it very painful to use EF Model First for things it doesn't provide easily. It gets ugly very fast, especially when messsing with the EDMX.
In case any comes across this post I found a solution to the problem which was to call an existing method in the code as follows:
_employeeRepository = new GenericRepository(new SidekickEntities());
GenericRepository is an object in the code that would take a DbContext directly.
I am trying to switch from LINQ2SQL to EF ... I am getting the following error with some code that originally worked with LINQ2SQL and seems to compile correctly:
Csla.DataPortalException:
DataPortal.Fetch failed (LINQ to
Entities does not recognize the method
'MyApp.Logic.UserInfo
FetchUserInfo(MyApp.Data.User)'
method, and this method cannot be
translated into a store expression.)
---> Csla.Reflection.CallMethodException:
DataPortal_Fetch method call failed
---> System.NotSupportedException: LINQ to Entities does not recognize
the method 'MyApp.Logic.UserInfo
FetchUserInfo(MyApp.Data.User)'
method, and this method cannot be
translat...
This is the code:
var data = query.Select(row => UserInfo.FetchUserInfo(row));
this.AddRange(data);
I'm trying to read a list of data and load the entities into my class. I'm new to EF and just think I am overlooking something.
Any help would be appreciated!
For those interested, the solution was:
var data = query.AsEnumerable().Select(UserInfo.FetchUserInfo);
As far as I can see the problem is that Linq to Entities provider knows nothing about how to translate you custom method FetchUserInfo to ESQL.
If UserInfo is just a DTO and UserInfo.FetchUserInfo is a kind of Entity to DTO conversion method this would help
var data = query.AsEnumerable().Select(row => UserInfo.FetchUserInfo(row));
.AsEnumerable() invoke will result in materialization of query results to memory objects.