1 /* 2 * Entity - Entity is an object-relational mapping tool for the D programming language. Referring to the design idea of JPA. 3 * 4 * Copyright (C) 2015-2018 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: HuntLabs.cn 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.entity.EntityFieldOneToMany; 13 14 import hunt.logging; 15 import hunt.entity; 16 import hunt.Exceptions; 17 import std.variant; 18 19 20 class EntityFieldOneToMany(T : Object, F : Object) : EntityFieldObject!(T,F) { 21 22 23 private OneToMany _mode; 24 private string _primaryKey; 25 // private string _joinColumn; 26 private string _findString; 27 private T[][string] _decodeCache; 28 29 this(EntityManager manager, string fieldName, string primaryKey, string tableName, OneToMany mode, F owner) { 30 super(manager, fieldName, "", tableName, null, owner); 31 init(primaryKey, mode, owner); 32 } 33 34 private void init(string primaryKey, OneToMany mode, F owner) { 35 _mode = mode; 36 _enableJoin = _mode.fetch == FetchType.EAGER; 37 _primaryKey = primaryKey; 38 _joinColumn = _entityInfo.getFields[_mode.mappedBy].getJoinColumn(); 39 initJoinData(); 40 initFindStr(); 41 } 42 43 private void initJoinData() { 44 _joinSqlData = new JoinSqlBuild(); 45 _joinSqlData.tableName = _entityInfo.getTableName(); 46 _joinSqlData.joinWhere = getTableName() ~ "." ~ _primaryKey ~ " = " ~ _entityInfo.getTableName() ~ "." ~ _joinColumn; 47 _joinSqlData.joinType = JoinType.LEFT; 48 foreach(value; _entityInfo.getFields()) { 49 _joinSqlData.columnNames ~= value.getSelectColumn(); 50 } 51 // logDebug("one to many join sql : %s ".format(_joinSqlData)); 52 } 53 54 override string getSelectColumn() { 55 return ""; 56 } 57 58 59 private void initFindStr() { 60 _findString = "SELECT "; 61 string[] el; 62 foreach(k,v; _entityInfo.getFields()) { 63 if (v.getSelectColumn() != "") 64 el ~= " "~v.getSelectColumn(); 65 } 66 foreach(k,v; el) { 67 _findString ~= v; 68 if (k != el.length -1) 69 _findString ~= ","; 70 } 71 _findString ~= " FROM "~_entityInfo.getTableName()~" WHERE " ~ _entityInfo.getTableName() ~"."~_joinColumn~" = "; 72 } 73 74 string getPrimaryKey() {return _primaryKey;} 75 OneToMany getMode() {return _mode;} 76 77 override FetchType fetchType() { 78 return _mode.fetch; 79 } 80 81 82 T[] deSerialize(Row[] rows, int startIndex, bool isFromManyToOne, F owner) { 83 version(HUNT_ENTITY_DEBUG) { 84 tracef("FetchType: %s, isFromManyToOne: %s", _mode.fetch, isFromManyToOne); 85 } 86 87 if (_mode.fetch == FetchType.LAZY) 88 return null; 89 90 T[] ret; 91 T singleRet; 92 long count = -1; 93 if (isFromManyToOne) { 94 string joinValue = getJoinKeyValue(rows[startIndex]); 95 if (joinValue == "") 96 return ret; 97 T[] rets = getValueByJoinKeyValue(joinValue); 98 foreach(value; rets) { 99 ret ~= Common.sampleCopy(value); 100 } 101 } else { 102 version(HUNT_ENTITY_DEBUG) warning("start"); 103 foreach(value; rows) { 104 singleRet = _entityInfo.deSerialize([value], count, 0, owner); 105 if (singleRet !is null) 106 // ret ~= Common.sampleCopy(singleRet); 107 ret ~= singleRet; // Common.sampleCopy(singleRet); 108 } 109 version(HUNT_ENTITY_DEBUG) warning("ended"); 110 } 111 return ret; 112 } 113 114 private string getJoinKeyValue(Row row) { 115 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName()); 116 Variant v = row.getValue(name); 117 if(!v.hasValue()) { 118 version(HUNT_DEBUG) warningf("Can't find value for %s", name); 119 return null; 120 } 121 122 string value = v.toString(); 123 version(HUNT_ENTITY_DEBUG) tracef("A column: %s = %s", name, value); 124 return value; 125 } 126 127 private T[] getValueByJoinKeyValue(string key) { 128 if (key in _decodeCache) 129 return _decodeCache[key]; 130 131 T[] ret; 132 T singleRet; 133 auto stmt = _manager.getSession().prepare(_findString~key); 134 auto res = stmt.query(); 135 long count = -1; 136 foreach(value; res) { 137 singleRet = _entityInfo.deSerialize([value], count); 138 if (singleRet) 139 ret ~= singleRet; 140 } 141 _decodeCache[key] = ret; 142 return _decodeCache[key]; 143 } 144 145 void setMode(OneToMany mode) { 146 _mode = mode; 147 _enableJoin = _mode.fetch == FetchType.EAGER; 148 } 149 150 override LazyData getLazyData(Row row) { 151 string name = EntityExpression.getColumnAsName(_primaryKey, getTableName()); 152 Variant v = row.getValue(name); 153 if(!v.hasValue()) { 154 version(HUNT_ENTITY_DEBUG) warningf("Can't find the value for the primary key: %s", name); 155 return null; 156 } 157 158 string value = v.toString(); 159 version(HUNT_ENTITY_DEBUG) { 160 infof("The referenced primary column: %s=%s, the current model: %s", 161 name, value, T.stringof); 162 } 163 164 LazyData ret = new LazyData(_mode.mappedBy, value); 165 return ret; 166 } 167 168 169 170 }