Base solution for your next web application
Open Closed

CONVERTING EXISTING SOLUTION INTO ABP - BEST PRACTICE #1903


User avatar
0
exlnt created

I posted this in other forum:

#1895

I would be glad to hear any inputs from others.

Thanks!


20 Answer(s)
  • User Avatar
    0
    exlnt created

    One additional question.

    How many of the Metronic themes are available to us as part of the licensed purchase? How do we switch to any of the other themes, if we wanted to, is there any documentation on this procedure?

    Thanks!

  • User Avatar
    0
    hikalkan created
    Support Team

    You have all metronic themes/layout here: <a class="postlink" href="http://keenthemes.com/preview/metronic/">http://keenthemes.com/preview/metronic/</a> AspNet Zero implements layout 4 material design. If you want to change to another theme, it requires manual work. HTML/CSS based themes are generally like that since different themes has different HTML structure and CSS classes. First you need to download Metronic files from here: <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero/releases/download/v1.13.0/metronic_v4.7.zip">https://github.com/aspnetzero/aspnet-ze ... c_v4.7.zip</a> Then open the layout you want, compare and change HTML code and change CSS files.

  • User Avatar
    0
    exlnt created

    I am following your step-by-step guide for the MVC app. However, would it be possible for you to share some more details, with code snippets, on how I can leverage our existing data access (with SPs) and/or business layer? We have a lot of tables with composite keys and FKs to other tables. I'm having trouble recreating all of these as-is using EF code first. This is something we have attempted to do before and have been unable to make it work.

    Thanks! E

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    In order to call a SP, you can create a custom repository and call the SP inside it. You have access to DbContext in custom repository methods. An example would be

    var entities = Context.Database.SqlQuery<YourEntity>("NameOfSP @Param1", new SqlParameter("@Param1", 1)).ToList();
    

    Moving an existing project to ABP is not easy, especially when creating entities. You can use a custom tool for generating your POCO classes. This might be a good one <a class="postlink" href="https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838">https://visualstudiogallery.msdn.micros ... 2fb90f5838</a>

    This will not give you a complete solution I think but it saves you so much time.

  • User Avatar
    0
    exlnt created

    What project in the ABP solution template should I create my custom repositories in?

    I cannot see any examples from the ABP solution as they are in the metadata. At least I cannot find the source code for it.

    Thx

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Define your repository interfaces in *.Core project and implement them in *.EntityFramework project. You can find a custom repository example in simple task system sample here <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/SimpleTaskSystem">https://github.com/aspnetboilerplate/as ... TaskSystem</a>.

    ITaskRepository <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/SimpleTaskSystem/SimpleTaskSystem.Core/Tasks/ITaskRepository.cs">https://github.com/aspnetboilerplate/as ... ository.cs</a>

    TaskRepository <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate-samples/blob/master/SimpleTaskSystem/SimpleTaskSystem.EntityFramework/EntityFramework/Repositories/TaskRepository.cs">https://github.com/aspnetboilerplate/as ... ository.cs</a>

  • User Avatar
    0
    exlnt created

    Thanks for providing those examples. They are helping.

    I have mirrored the task repository code for one of my custom entities. I have created the Interface and implemented it just like the task example. Now when I setup a test method to validate the code. I keep getting the error below.

    <span style="color:#FF0000">Message=Can not instantiate proxy of class: MyCmp.MyProject.EntityFramework.Repositories.ListValuesRepository. Could not find a parameterless constructor.</span>

    It fails soon as the test class tries to instantiate the app service.

    Here is the Interface code:

    using System.Threading.Tasks;
    using Abp.Application.Services;
    using Abp.Application.Services.Dto;
    using EXLNT.NursingOps17.NursingOps.Dto;
    using System.Collections.Generic;
    
    namespace EXLNT.NursingOps17.NursingOps
    {
        public interface IListValuesAppService : IApplicationService
        {
    
            ListResultDto<ListValuesListDto> GetListValues(string ListName = "");
    
        }
    }
    

    Here is the app service code:

    using Abp.Application.Services.Dto;
    using Abp.AutoMapper;
    using Abp.Collections.Extensions;
    using EXLNT.NursingOps17.NursingOps.Dto;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EXLNT.NursingOps17.NursingOps
    {
        
        public class ListValuesAppService : NursingOps17AppServiceBase, IListValuesAppService
        {
    
            private readonly IListValuesRepository _listvaluesRepository;
    
    
            /// <summary>
            ///In constructor, we can get needed classes/interfaces.
            ///They are sent here by dependency injection system automatically.
            /// </summary>
            public ListValuesAppService(IListValuesRepository listvaluesRepository)
            {
                _listvaluesRepository = listvaluesRepository;
            }
    
            public List<ComboboxItemDto> GetListValuesComboboxItems(int? selectedListValue = default(int?))
            {
                throw new NotImplementedException();
            }
    
            public ListResultDto<ListValuesListDto> GetListValues(string ListName = "")
            {
                var listvalues = _listvaluesRepository.GetAll().WhereIf(
                     ListName.Length != 0,  p => p.ListName == ListName)
                 .OrderBy(p => p.ListName)
                 .ThenBy(p => p.ListValue)
                 .ToList();
                return new ListResultDto<ListValuesListDto>(listvalues.MapTo<List<ListValuesListDto>>());
            }
    
    
        }
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Can you share your repository interface and implementation ?

  • User Avatar
    0
    exlnt created

    Here is the repository code:

    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using Abp.EntityFramework;
    using EXLNT.NursingOps17.NursingOps;
    
    namespace EXLNT.NursingOps17.EntityFramework.Repositories
    {
        public class ListValuesRepository : NursingOps17RepositoryBase<ListValues, int>, IListValuesRepository
        {
            protected ListValuesRepository(IDbContextProvider<NursingOps17DbContext> dbContextProvider)
                : base(dbContextProvider)
            {
            }
    
            public List<ListValues> GetAllByValue(int? id, string listName)
            {
                //In repository methods, we do not deal with create/dispose DB connections, DbContexes and transactions. ABP handles it.
    
                var query = GetAll(); //GetAll() returns IQueryable<T>, so we can query over it.
    
                //Add some Where conditions...
    
                if (listName.Length != 0)
                {
                    query = query.Where(task => task.ListName == listName);
                }
    
                if (id.HasValue)
                {
                    query = query.Where(task => task.Id == id);
                }
    
                return query
                    .OrderByDescending(task => task.ListValue)
                    .ToList();
            }
    
        }//class
    }
    

    The interface and implementation is on my previous post.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Does IListValuesRepository implements IRepository ?

  • User Avatar
    0
    exlnt created

    Yes. See below.

    namespace EXLNT.NursingOps17.NursingOps
    {
        public interface IListValuesRepository : IRepository<ListValues, int>
        {
            /// <summary>
            /// Gets all list values with <see cref="ListValues.ListName"/> is retrived (Include for EntityFramework, Fetch for NHibernate)
            /// filtered by given conditions.
            /// </summary>
            /// <param name="listName">List name filter. If it's null, not filtered.</param>
            /// <returns>List of values by name</returns>
            List<ListValues> GetAllByValue(int? listID, string listName);
        }
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    I have found your problem. Constructor of ListValuesRepository must be public not protected in order to inject it with dependency injection.

  • User Avatar
    0
    exlnt created

    Thank you, that resolved the error!

    New issue, the repository method GetAll() is NOT returning any data? Am I missing something?

    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using Abp.EntityFramework;
    using EXLNT.NursingOps17.NursingOps;
    
    namespace EXLNT.NursingOps17.EntityFramework.Repositories
    {
        public class ListValuesRepository : NursingOps17RepositoryBase<ListValues, int>, IListValuesRepository
        {
            public ListValuesRepository(IDbContextProvider<NursingOps17DbContext> dbContextProvider)
                : base(dbContextProvider)
            {
            }
    
            public List<ListValues> GetListNameValues(string listName)
            {
                //In repository methods, we do not deal with create/dispose DB connections, DbContexes and transactions. ABP handles it.
    
                var query = GetAll(); //GetAll() returns IQueryable<T>, so we can query over it.
                //var query = Context.Tasks.AsQueryable(); //Alternatively, we can directly use EF's DbContext object.
                //var query = Table.AsQueryable(); //Another alternative: We can directly use 'Table' property instead of 'Context.Tasks', they are identical.
    
                //Add some Where conditions...
    
                if (listName.Length != 0)
                {
                    query = query.Where(task => task.ListName == listName);
                }
    
                //if (id.HasValue)
                //{
                //    query = query.Where(task => task.Id == id);
                //}
    
                return query
                    .OrderByDescending(task => task.ListValue)
                    .ToList();
            }
    
        }//class
    }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    Can you check the executed sql query via SQL query profiler ? If you cannot solve the problem, can you send a screenshot of your ListValues database table ?

  • User Avatar
    0
    exlnt created

    <cite>ismcagdas: </cite> Hi,

    Can you check the executed sql query via SQL query profiler ? If you cannot solve the problem, can you send a screenshot of your ListValues database table ?

    Thanks but I was able to get past this error. Not sure what I changed :-) but the default GetAll() method started working and returning data. I have got my create, get and update methods working now using the existing design pattern.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Great :)

  • User Avatar
    0
    exlnt created

    Strangely I am getting this error message again, on combobox load method.

    Only parameterless constructors and initializers are supported in LINQ to Entities.
    

    Here is where the error happens: [https://drive.google.com/open?id=0B5HAoiVVXzY7aFEyS183VGRHSU0])

    I checked and the constructor is public already. ;)

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    You cannot use ComboboxItemDto with it's constructor in linq expression. As the error says "Only parameterless constructors and initializers are supported in LINQ to Entities."

    You can change it to,

    e=> new ComboboxItemDto{
        Value = e.Id.ToString(),
        Text = e.CountryName
    }
    
  • User Avatar
    0
    exlnt created

    I copied that code from the ABP code in the editions app service, see below. I am using this exact same code for another entity and it works just fine there too.

    //Edition app service method
                //var editionItems = new ListResultDto<ComboboxItemDto>(editions.Select(e => new ComboboxItemDto(e.Id.ToString(), e.DisplayName)).ToList()).Items.ToList();
    
              //country app service method
                var countryItems = new ListResultDto<ComboboxItemDto>(countries.Select(e => new ComboboxItemDto(e.Id.ToString(), e.CountryName)).ToList()).Items.ToList();
    

    Why does it not work here?

    public async Task<List<ComboboxItemDto>> GetEditionComboboxItems(int? selectedEditionId = null)
            {
                var editions = await _editionManager.Editions.ToListAsync();
                var editionItems = new ListResultDto<ComboboxItemDto>(editions.Select(e => new ComboboxItemDto(e.Id.ToString(), e.DisplayName)).ToList()).Items.ToList();
    
                var defaultItem = new ComboboxItemDto("null", L("NotAssigned"));
                editionItems.Insert(0, defaultItem);
    

    Also, I could not get your suggested code to work either. It gives syntax error soon as the statement is coded.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    The difference is, in your failed version you use IQueryable using _countryRepository.GetAll(). But, EditionAppService a List of Edtions which is already retrieved from database.

    If you don't do any filter on countries, you can use _countryRepository.GetAllList(); and it will work in this way. Otherwise, you can use it like this.

    var countryItems = new ListResultDto<ComboboxItemDto>(countries.Select(e=> new ComboboxItemDto
    {
        DisplayText = e.CountryName,
        Value = e.Id.ToString()
    }).ToList()).Items.ToList();