我被困在这一段时间,我很难过。 Automapper需要4秒钟来映射19个对象。我的机器上的操作应该花费几毫秒或几纳秒(24gb ram,3.6Ghz i7)。
这是映射调用。
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
using System.Linq;
struct ObjMaterial
{
public string name;
public string textureName;
}
public class Menu : MonoBehaviour {
public int window;
void Start () {
window = 1;
}
private static int vertexOffset = 0;
private static int normalOffset = 0;
private static int uvOffset = 0;
//User should probably be able to change this. It is currently left as an excercise for
//the reader.
private static string targetFolder = "ExportedObj";
private static string MeshToString(Component mf, Dictionary<string, ObjMaterial> materialList)
{
Mesh m;
Material[] mats;
if(mf is MeshFilter)
{
m = (mf as MeshFilter).mesh;
mats = mf.GetComponent<Renderer>().sharedMaterials;
}
else if(mf is SkinnedMeshRenderer)
{
m = (mf as SkinnedMeshRenderer).sharedMesh;
mats = (mf as SkinnedMeshRenderer).sharedMaterials;
}
else
{
return "";
}
StringBuilder sb = new StringBuilder();
sb.Append("g ").Append(mf.name).Append("\n");
foreach(Vector3 lv in m.vertices)
{
Vector3 wv = mf.transform.TransformPoint(lv);
//This is sort of ugly - inverting x-component since we're in
//a different coordinate system than "everyone" is "used to".
sb.Append(string.Format("v {0} {1} {2}\n",-wv.x,wv.y,wv.z));
}
sb.Append("\n");
foreach(Vector3 lv in m.normals)
{
Vector3 wv = mf.transform.TransformDirection(lv);
sb.Append(string.Format("vn {0} {1} {2}\n",-wv.x,wv.y,wv.z));
}
sb.Append("\n");
foreach(Vector3 v in m.uv)
{
sb.Append(string.Format("vt {0} {1}\n",v.x,v.y));
}
for (int material=0; material < m.subMeshCount; material ++) {
sb.Append("\n");
sb.Append("usemtl ").Append(mats[material].name).Append("\n");
sb.Append("usemap ").Append(mats[material].name).Append("\n");
//See if this material is already in the materiallist.
try
{
ObjMaterial objMaterial = new ObjMaterial();
objMaterial.name = mats[material].name;
objMaterial.textureName = EditorUtility.GetAssetPath(mats[material].mainTexture);
//else
//objMaterial.textureName = null;
materialList.Add(objMaterial.name, objMaterial);
}
catch (ArgumentException)
{
//Already in the dictionary
}
int[] triangles = m.GetTriangles(material);
for (int i=0;i<triangles.Length;i+=3)
{
//Because we inverted the x-component, we also needed to alter the triangle winding.
sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
triangles[i]+1 + vertexOffset, triangles[i+1]+1 + normalOffset, triangles[i+2]+1 + uvOffset));
}
}
vertexOffset += m.vertices.Length;
normalOffset += m.normals.Length;
uvOffset += m.uv.Length;
return sb.ToString();
}
private static void Clear()
{
vertexOffset = 0;
normalOffset = 0;
uvOffset = 0;
}
private static Dictionary<string, ObjMaterial> PrepareFileWrite()
{
Clear();
return new Dictionary<string, ObjMaterial>();
}
private static void MaterialsToFile(Dictionary<string, ObjMaterial> materialList, string folder, string filename)
{
using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl"))
{
foreach( KeyValuePair<string, ObjMaterial> kvp in materialList )
{
sw.Write("\n");
sw.Write("newmtl {0}\n", kvp.Key);
sw.Write("Ka 0.6 0.6 0.6\n");
sw.Write("Kd 0.6 0.6 0.6\n");
sw.Write("Ks 0.9 0.9 0.9\n");
sw.Write("d 1.0\n");
sw.Write("Ns 0.0\n");
sw.Write("illum 2\n");
if (kvp.Value.textureName != null)
{
string destinationFile = kvp.Value.textureName;
int stripIndex = destinationFile.LastIndexOf('/');//FIXME: Should be Path.PathSeparator;
if (stripIndex >= 0)
destinationFile = destinationFile.Substring(stripIndex + 1).Trim();
string relativeFile = destinationFile;
destinationFile = folder + "/" + destinationFile;
Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);
try
{
//Copy the source file
File.Copy(kvp.Value.textureName, destinationFile);
}
catch
{
}
sw.Write("map_Kd {0}", relativeFile);
}
sw.Write("\n\n\n");
}
}
}
private static void MeshToFile(Component mf, string folder, string filename)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
{
sw.Write("mtllib ./" + filename + ".mtl\n");
sw.Write(MeshToString(mf, materialList));
}
MaterialsToFile(materialList, folder, filename);
}
private static void MeshesToFile(Component[] mf, string folder, string filename)
{
Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();
using (StreamWriter sw = new StreamWriter(folder +"/" + filename + ".obj"))
{
sw.Write("mtllib ./" + filename + ".mtl\n");
for (int i = 0; i < mf.Length; i++)
{
sw.Write(MeshToString(mf[i], materialList));
}
}
MaterialsToFile(materialList, folder, filename);
}
private static bool CreateTargetFolder()
{
try
{
System.IO.Directory.CreateDirectory(targetFolder);
}
catch
{
//EditorUtility.DisplayDialog("Error!", "Failed to create target folder!", "");
return false;
}
return true;
}
void OnGUI () {
GUI.BeginGroup (new Rect (Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 200));
if(window == 1)
{
if(GUI.Button (new Rect (10,30,180,30), "Экспортировать"))
{
if (!CreateTargetFolder())
return;
//GameObject[] gos = GameObject.FindGameObjectsWithTag("Boat");
//Selection.objects = gos;
GameObject[] selection = GameObject.FindGameObjectsWithTag("Boat");
//Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
if (selection.Length == 0)
{
//EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
return;
}
int exportedObjects = 0;
ArrayList mfList = new ArrayList();
for (int i = 0; i < selection.Length; i++)
{
Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter)).Concat(selection[i].GetComponentsInChildren(typeof(SkinnedMeshRenderer))).ToArray();
for (int m = 0; m < meshfilter.Length; m++)
{
exportedObjects++;
mfList.Add(meshfilter[m]);
}
}
if (exportedObjects > 0)
{
Component[] mf = new Component[mfList.Count];
for (int i = 0; i < mfList.Count; i++) {
mf [i] = (Component)mfList [i];
}
string filename = /*EditorApplication.currentScene +*/ "_" + exportedObjects;
int stripIndex = filename.LastIndexOf ('/');//FIXME: Should be Path.PathSeparator
if (stripIndex >= 0)
filename = filename.Substring (stripIndex + 1).Trim ();
MeshesToFile (mf, targetFolder, filename);
}
}
if(GUI.Button (new Rect (10,150,180,30), "Выход"))
{
window = 5;
}
}
if(window == 5)
{
GUI.Label(new Rect(50, 10, 180, 30), "Вы уже выходите?");
if(GUI.Button (new Rect (10,40,180,30), "Да"))
{
Application.Quit();
}
if(GUI.Button (new Rect (10,80,180,30), "Нет"))
{
window = 1;
}
}
GUI.EndGroup ();
}
}
这是我的Automapper配置
var messageDtos = AutoMapperConfig.Mapper.Map<List<Message>, List<MessageDTO>>(messages);
以下是相关对象。他们并不疯狂。
public static class AutoMapperConfig
{
public static IMapper Mapper;
public static void Configure()
{
MapperConfiguration config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDTO>();
cfg.CreateMap<UserDTO, User>();
cfg.CreateMap<ConversationUser, ConversationUserDTO>();
cfg.CreateMap<ConversationUserDTO, ConversationUser>();
cfg.CreateMap<Conversation, ConversationDTO>();
cfg.CreateMap<ConversationDTO, Conversation>()
.ForMember(dest => dest.ConversationUsers, opt => opt.MapFrom(src => src.ConversationUsers));
cfg.CreateMap<Message, MessageDTO>();
cfg.CreateMap<MessageDTO, Message>();
});
Mapper = config.CreateMapper();
}
}
这是一个点迹线的屏幕截图,显示Automapper的使用时间,不确定它提供了多少洞察力,我昨天刚刚安装了dotrace来解决这个问题。
答案 0 :(得分:3)
简而言之,正在进行数据库调用。
AutoMapper正在调用您的关系属性getter,它正在使用EntityFramework从数据库加载数据。
快速解决方法是禁用延迟加载的集合。
答案 1 :(得分:2)
您的Message
类是Entity Framework模型的一部分,您似乎启用了延迟加载。因此,在从Message
类映射时,属性MediaMessages
和ReadReceipts
尚未从数据库加载,而AutoMapper会触发它们延迟加载。因此,这4秒实际上是映射期间发生的2个数据库调用。
在映射实体之前,您应该急切地加载实体。可能更好的方法是在查询期间禁用延迟加载并手动.Include()
。