简体   繁体   中英

“The type RoleProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.” NHibernate

So as the title says: Im getting an error which says: "System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type RoleProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."

Im trying to return a list of users in database as XML in web services (the password exclusive).

Here's some code:

MS SQL Server Database:

User Table:

CREATE TABLE [dbo].[Users] (
    [Id]       NVARCHAR (50) NOT NULL,
    [Username] NVARCHAR (50) NULL,
    [Password] NVARCHAR (50) NOT NULL,
    [Role]     NVARCHAR (50) NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_Users_Role] FOREIGN KEY ([Role]) REFERENCES [dbo].[Role] ([Id])
);

Role Table:

CREATE TABLE [dbo].[Role] (
    [Id]   NVARCHAR (50) NOT NULL,
    [Name] NVARCHAR (50) NULL,
    CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED ([Id] ASC)
);

WebService.cs

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Services;
using NHibernate;
using Models;
using NHibernate.Mapping;

[WebService(Namespace = "http://LambdAlarm.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class LambdAlarmWebService : WebService
{
    [WebMethod]
    public List<Users> GetUser()
    {
        var factory = SessionFactory.Instance;
        var session = factory.OpenSession();
        var result = session.QueryOver<Users>().List<Users>();

        return result.ToList(); //Where I suspect the error occurs.
    }
}

Users.cs (Model)

namespace Models
{
    public class Users : EntityBase
    {
        public virtual string Username { get; set; }
        public virtual string Password { get; set; }
        public virtual Role Role { get; set; }
    }
}

Role.cs:

namespace Models
{
    public class Role : EntityBase
    {
        public virtual string Name { get; set; }
    }
}

EntityBase: (Class with property guid which is inherited in all models)

using System;

namespace Models
{
    public class EntityBase
    {
        public virtual Guid Id { get; set; }
    }
}

UserMap:

using FluentNHibernate.Mapping;
using Models;

namespace NHibernate.Mapping
{
    public class UserMap : ClassMap<Users>
    {
        public UserMap()
        {
            Table("Users");
            Id(x => x.Id).GeneratedBy.GuidComb();
            LazyLoad();
            References(x => x.Role).Column("Role");
            Map(x => x.Username).Column("Username");
            Map(x => x.Password).Column("Password").Not.Nullable();
        }
    }
}

RoleMap:

using FluentNHibernate.Mapping;
using Models;

namespace NHibernate.Mapping
{
    public class RoleMap : ClassMap<Role>
    {
        public RoleMap()
        {
            Table("Role");
            Id(x => x.Id).GeneratedBy.GuidComb();
            LazyLoad();
            Map(x => x.Name).Column("Name");
        }
    }
}

SessionFactory:

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using Models;
using NHibernate.Conventions;

namespace NHibernate
{
    public static class SessionFactory
    {
        private static ISessionFactory _sessionFactory;

        public static ISessionFactory Instance
        {
            get
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = CreateSessionFactory();
                }

                return _sessionFactory;
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                        .Database(MsSqlConfiguration.MsSql2012
                            .ConnectionString(c => c.FromConnectionStringWithKey("DatabaseConnectionString")))
                        .Mappings(m =>
                        {
                            m.FluentMappings.Conventions.AddFromAssemblyOf<CustomForeignKeyConvention>();
                            m.FluentMappings.AddFromAssemblyOf<EntityBase>();
                        })
                        .BuildSessionFactory();
        }
    }
}

Conventions:

using FluentNHibernate;
using FluentNHibernate.Conventions;

namespace NHibernate.Conventions
{
    public class CustomForeignKeyConvention : ForeignKeyConvention
    {
        protected override string GetKeyName(Member property, System.Type type)
        {
            if (property == null)
            {
                return type.Name;
            }

            return property.Name;
        }
    }
}

Anyone know what the problem is? Help will appreciated!

your are not telling NHibernate what you need so it will lazyload all references objects. This however will generate proxies. The simplest solution which will also prevent SELECT N+1 is to eager load the roles. Also get rid of the redundnant copying of the result list.

[WebMethod]
public List<Users> GetUser()
{
    var factory = SessionFactory.Instance;
    using (var session = factory.OpenSession())
    {
        return session.QueryOver<Users>().Fetch(u => u.Role).List();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM