Search code examples
c#asp.net-mvcjsonkendo-gridllblgenpro

Convert LLBLGen model class to View Model objects?


I do not think I worded the title correctly. I am trying to return results to populate a view. the error message I get in the browser console is "A circular reference was detected while serializing an object of type" all of the documentation says to flatten out the object and exclude properties that are not related to the model. creating a anonymous type is a work around that seems to work for some. I cannot get either to work. if I try something like

var Results = from RS in results
                      select new
                      {
                          BundleId = RS.BundleId
                      };

intellisense does pick it up. Any suggestions?

Controller

{
public class BundleStatusController : Controller
{


    public ActionResult BundleStatus()
    {
        return View();

    }

    [HttpPost]
    public ActionResult BundleStatusRead([DataSourceRequest] DataSourceRequest request)
    {

            var span = DateTime.Today.AddDays(-1);
            DataAccessAdapter adapter = new DataAccessAdapter();
            EntityCollection allBundles = new EntityCollection(new CarrierBundleEntityFactory());
            RelationPredicateBucket filter = new RelationPredicateBucket(CarrierBundleFields.Date <= span);
            adapter.FetchEntityCollection(allBundles, filter);
            var results = allBundles;

            return Json(results.ToDataSourceResult(request));
        }

}

}

View

  @{
ViewBag.Title = "BundleStatusGet";
 }

 <div>
@(Html.Kendo().Grid<ZoomAudits.DAL.EntityClasses.CarrierBundleEntity>()
    .Name("grid")
    .Columns(columns =>
    {
        columns.Bound(c => c.BundleId).Width(140);
        columns.Bound(c => c.CarrierId).Width(190);
        columns.Bound(c => c.Date);
        columns.Bound(c => c.IsSent).Width(110);
    })
    .HtmlAttributes(new { style = "height: 380px;" })
    .Scrollable()
    .Groupable()
    .Sortable()
    .Pageable(pageable => pageable
        .Refresh(true)
        .PageSizes(true)
        .ButtonCount(5))
                .Selectable(selectable => selectable
                .Mode(GridSelectionMode.Multiple)
                .Type(GridSelectionType.Cell))
            //.Events(events => events.Change("onChange").Sync("sync_handler")))
    .DataSource(dataSource => dataSource
        .Ajax()
        .Read(read => read.Action("BundleStatusRead", "BundleStatus"))
                //.Update(update => update.Action("EditingInline_Update", "Grid"))
    )
)

UPDATED CONTROLLER

[HttpPost]
    public ActionResult BundleStatusRead([DataSourceRequest] DataSourceRequest request)
    {

        var span = DateTime.Today.AddDays(-1);
        DataAccessAdapter adapter = new DataAccessAdapter();
        EntityCollection allBundles = new EntityCollection(new CarrierBundleEntityFactory());
        RelationPredicateBucket filter = new RelationPredicateBucket(CarrierBundleFields.Date <= span);
        adapter.FetchEntityCollection(allBundles, filter);


        //...Using AutoMapper
        **Mapper**.CreateMap<UtilityWebSite.Models.CarrierBundleModel, ZoomAudits.DAL.EntityClasses.CarrierBundleEntity>();
        List<UtilityWebSite.Models.CarrierBundleModel> viewModelList = Mapper.Map<List<ZoomAudits.DAL.EntityClasses.CarrierBundleEntity>, List<UtilityWebSite.Models.CarrierBundleModel>>(allBundles);
        return Json(viewModelList.ToDataSourceResult(request));

        //...Not using AutoMapper
        List<UtilityWebSite.Models.CarrierBundleModel> viewBundles = new List<UtilityWebSite.Models.CarrierBundleModel>();
        foreach (ZoomAudits.DAL.EntityClasses.CarrierBundleEntity entityBundle in **EntityCollection**)
        {
            UtilityWebSite.Models.CarrierBundleModel model = new UtilityWebSite.Models.CarrierBundleModel();
            model.BundleID = entityBundle.BundleId;
            model.CarrierId = entityBundle.CarrierId;
            viewBundles.Add(model);
        }
        return Json(viewBundles.ToDataSourceResult(request));

    }

Solution

  • You are facing an issue where your Data Entity object needs to be separated from your Model objects. At first this seems like more work than needed, but as your application grows you will see the benefit in duplicating you classes. Here is how I would go about it.

    In your LLBLGEN Domain Class

    namespace ZoomAudits.DAL.EntityClasses
    {
        public class CarrierBundleEntity
        {
           //....Whatever is generated as your Bundle object from the DB
        }
    }
    

    In your Models MVC Folder

    namespace MyProjectNamespace.Models
    {
        public class CarrierBundleModel
        {
            [Required]
            [Display(Name = "Bundle ID")]
            public int BundleID{get;set;}
    
            [Required]
            [Display(Name = "Bundle Name")]
            public int BundleName{get;set;}
    
            //...Other properties you will use in the UI That match the LLBLGen Bundle class  
        }
    }
    

    In your Controller Action

    [HttpPost]
    public ActionResult BundleStatusRead([DataSourceRequest] DataSourceRequest request)
    {                   
    
            var span = DateTime.Today.AddDays(-1);
            DataAccessAdapter adapter = new DataAccessAdapter();
            EntityCollection allBundles = new EntityCollection(new CarrierBundleEntityFactory());
            RelationPredicateBucket filter = new RelationPredicateBucket(CarrierBundleFields.Date <= span);
            adapter.FetchEntityCollection(allBundles, filter);
    
    
            //...Using AutoMapper
            Mapper.CreateMap<MyProjectNamespace.Models.CarrierBundleModel, ZoomAudits.DAL.EntityClasses.CarrierBundleEntity>();   
            List<MyProjectNamespace.Models.CarrierBundleModel> viewModelList =Mapper.Map<List<ZoomAudits.DAL.EntityClasses.CarrierBundleEntity>, List<MyProjectNamespace.Models.CarrierBundleModel>>(allBundles);
            return Json(viewModelList.ToDataSourceResult(request));
    
            //...Not using AutoMapper
            List<MyProjectNamespace.Models.CarrierBundleModel> viewBundles=new List<MyProjectNamespace.Models.CarrierBundleModel>();
            foreach(ZoomAudits.DAL.EntityClasses.CarrierBundleEntity entityBundle in allBundles)
            {
                MyProjectNamespace.Models.CarrierBundleModel model=new MyProjectNamespace.Models.CarrierBundleModel();
                model.BundleID=entityBundle.BundleId;
                model.CarrierId=entityBundle.CarrierId;
                viewBundles.Add(model);
            }
            return Json(viewBundles.ToDataSourceResult(request));
    
    }
    

    In your View

    @(Html.Kendo().Grid<MyProject.Models.CarrierBundleModel>()
    

    NOTE: I use AutoMapper which is a great mapping library that you can add to your project and never have to write translations if there is a one to one match between your model and entity data types and names. There are other mapping tools available. I just included to show you an alternative shortcut to translating from DAL entity to Model.